home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / unix / volume23 / trn / part04 < prev    next >
Encoding:
Text File  |  1991-08-22  |  64.0 KB  |  2,665 lines

  1. This is a new archive version of TRN at patchlevel 3.
  2. The original posting took up Volume23, issues 60 to 73, with
  3. various problems.  These files replace those issues.
  4.  
  5. #! /bin/sh
  6. # This is a shell archive.  Remove anything before this line, then feed it
  7. # into a shell via "sh file" or similar.  To overwrite existing files,
  8. # type "sh file -c".
  9. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  10. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  11. # Contents:  art.c ng.c
  12. # Wrapped by rsalz@litchi.bbn.com on Fri Aug 23 16:38:53 1991
  13. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  14. echo If this archive is complete, you will see the following message:
  15. echo '          "shar: End of archive 4 (of 14)."'
  16. if test -f 'art.c' -a "${1}" != "-c" ; then 
  17.   echo shar: Will not clobber existing file \"'art.c'\"
  18. else
  19.   echo shar: Extracting \"'art.c'\" \(26201 characters\)
  20.   sed "s/^X//" >'art.c' <<'END_OF_FILE'
  21. X/* $Header: art.c,v 4.3.3.3 91/01/16 02:20:45 davison Trn $
  22. X *
  23. X * $Log:    art.c,v $
  24. X * Revision 4.3.3.3  91/01/16  02:20:45  davison
  25. X * Integrated rn patches 48-54.
  26. X * 
  27. X * Revision 4.3.3.2  90/08/20  16:05:33  davison
  28. X * Fixed bug in backpage code.
  29. X * 
  30. X * Revision 4.3.3.1  90/06/20  22:35:51  davison
  31. X * Initial Trn Release
  32. X * 
  33. X * Revision 4.3.2.9  90/12/10  01:34:42  sob
  34. X * "8 bit clean" mods and fixes for rn -e -L problems.
  35. X * 
  36. X * Revision 4.3.2.8  90/12/04  02:49:12  sob
  37. X * Added long lost commands control-P and control-N back into rn.
  38. X * 
  39. X * Revision 4.3.2.7  90/11/22  13:48:59  sob
  40. X * Added changes that will hopefully fix the "long lines" bug.
  41. X * 
  42. X * Revision 4.3.2.6  90/10/01  21:14:36  sob
  43. X * Shifted to fileno to increase portability.
  44. X * 
  45. X * Revision 4.3.2.5  90/10/01  21:05:22  sob
  46. X * Removed an extra closing paren.
  47. X * 
  48. X * Revision 4.3.2.4  90/10/01  02:01:53  sob
  49. X * Fix provided by earle@sun.com to alter rn's assumption of how to turn
  50. X * off underline mode when at the end of a line.
  51. X * 
  52. X * Revision 4.3.2.3  90/04/21  14:43:27  sob
  53. X * Revised previous patch insure that it does not decrement below zero.
  54. X * 
  55. X * Revision 4.3.2.2  90/03/22  23:03:25  sob
  56. X * Fixes provided by Wayne Davison <drivax!davison>
  57. X * 
  58. X * Revision 4.3.2.1  89/11/07  23:20:57  sob
  59. X * Bug fixes for NNTP
  60. X * 
  61. X * Revision 4.3.1.5  85/09/10  11:07:18  lwall
  62. X * %m not restored on some returns.
  63. X * 
  64. X * Revision 4.3.1.4  85/05/23  12:13:31  lwall
  65. X * shouldn't display article that's really a subdirectory.
  66. X * 
  67. X * Revision 4.3.1.3  85/05/13  09:29:55  lwall
  68. X * Added CUSTOMLINES option.
  69. X * 
  70. X * Revision 4.3.1.2  85/05/10  13:46:07  lwall
  71. X * Fixed header reparse bug on backpage.
  72. X * 
  73. X * Revision 4.3.1.1  85/05/10  11:30:56  lwall
  74. X * Branch for patches.
  75. X * 
  76. X * Revision 4.3  85/05/01  11:34:51  lwall
  77. X * Baseline for release with 4.3bsd.
  78. X * 
  79. X */
  80. X
  81. X#include "EXTERN.h"
  82. X#include "common.h"
  83. X#include "rn.h"
  84. X#include "ngstuff.h"
  85. X#include "ngdata.h"
  86. X#include "head.h"
  87. X#include "cheat.h"
  88. X#include "help.h"
  89. X#include "search.h"
  90. X#include "artio.h"
  91. X#include "ng.h"
  92. X#include "bits.h"
  93. X#include "final.h"
  94. X#include "artstate.h"
  95. X#include "rcstuff.h"
  96. X#include "term.h"
  97. X#include "sw.h"
  98. X#include "util.h"
  99. X#include "backpage.h"
  100. X#include "intrp.h"
  101. X#ifdef USETHREADS
  102. X#include "rthreads.h"
  103. X#endif
  104. X#include "INTERN.h"
  105. X#include "art.h"
  106. X
  107. X/* page_switch() return values */
  108. X
  109. X#define PS_NORM 0
  110. X#define PS_ASK 1
  111. X#define PS_RAISE 2
  112. X#define PS_TOEND 3
  113. X
  114. Xbool special = FALSE;        /* is next page special length? */
  115. Xint slines = 0;            /* how long to make page when special */
  116. XART_LINE highlight = -1;    /* next line to be highlighted */
  117. Xchar *restart = Nullch;        /* if nonzero, the place where last */
  118. X                /* line left off on line split */
  119. Xchar *blinebeg;            /* where in buffer current line began */
  120. XART_POS alinebeg;        /* where in file current line began */
  121. X
  122. X#ifdef INNERSEARCH
  123. XART_POS innersearch = 0;    /* artpos of end of line we found */
  124. X                /* for 'g' command */
  125. XART_LINE isrchline = 0;            /* last line to display */
  126. Xbool hide_everything = FALSE;
  127. X                /* if set, do not write page now, */
  128. X                /* but refresh when done with page */
  129. XCOMPEX gcompex;                /* in article search pattern */
  130. X#endif
  131. X
  132. Xbool firstpage;            /* is this the 1st page of article? */
  133. X
  134. Xchar art_buf[LBUFLEN];        /* place for article lines */
  135. X
  136. Xvoid
  137. Xart_init()
  138. X{
  139. X    ;
  140. X}
  141. X
  142. Xint
  143. Xdo_article()
  144. X{
  145. X    register char *s;
  146. X    ART_POS artsize;            /* size in bytes of article */
  147. X    bool hide_this_line = FALSE;    /* hidden header line? */
  148. X    ART_LINE linenum;    /* line # on page, 1 origin */
  149. X#ifdef ULSMARTS
  150. X    bool under_lining = FALSE;
  151. X                /* are we underlining a word? */
  152. X#endif
  153. X    register char *bufptr = art_buf;
  154. X                /* pointer to input buffer */
  155. X    register int outpos;    /* column position of output */
  156. X    static char prompt_buf[64];        /* place to hold prompt */
  157. X    bool notesfiles = FALSE;        /* might there be notesfiles junk? */
  158. X    char oldmode = mode;
  159. X    char *ctime();
  160. X
  161. X#ifdef INNERSEARCH
  162. X    register int outputok;
  163. X#endif
  164. X
  165. X/*  if (fstat(artfp->_file,&filestat)) ... does not work on Apollos */
  166. X    if (fstat(fileno(artfp),&filestat))
  167. X                /* get article file stats */
  168. X    return DA_CLEAN;
  169. X    if ((filestat.st_mode & S_IFMT) != S_IFREG)
  170. X    return DA_NORM;
  171. X    artsize = filestat.st_size;
  172. X                /* from that get article size */
  173. X    sprintf(prompt_buf,
  174. X    "%%sEnd of article %ld (of %ld)--what next? [%%s]",
  175. X    (long)art,(long)lastart);    /* format prompt string */
  176. X    prompt = prompt_buf;
  177. X    int_count = 0;        /* interrupt count is 0 */
  178. X    firstpage = (topline < 0);
  179. X    for (;;) {            /* for each page */
  180. X#ifdef USETHREADS
  181. X    if (max_tree_lines)
  182. X        init_tree();    /* init tree display */
  183. X#endif
  184. X    assert(art == openart);
  185. X    if (do_fseek) {
  186. X#ifdef ASYNC_PARSE
  187. X        parse_maybe(art);        /* make sure header is ours */
  188. X#endif
  189. X        artpos = vrdary(artline);
  190. X        if (artpos < 0)
  191. X        artpos = -artpos;    /* labs(), anyone? */
  192. X        if (firstpage)
  193. X        artpos = (ART_POS)0;
  194. X        fseek(artfp,artpos,0);
  195. X        if (artpos < htype[PAST_HEADER].ht_minpos)
  196. X        in_header = SOME_LINE;
  197. X        do_fseek = FALSE;
  198. X        restart = Nullch;
  199. X    }
  200. X    linenum = 1;
  201. X    if (firstpage) {
  202. X        if (firstline) {
  203. X        interp(art_buf, (sizeof art_buf), firstline);
  204. X#ifdef USETHREADS
  205. X        linenum += tree_puts(art_buf,linenum+topline,0);
  206. X#else
  207. X#ifdef CLEAREOL
  208. X        maybe_eol();    
  209. X#endif /* CLEAREOL */
  210. X        fputs(art_buf,stdout) FLUSH;
  211. X        linenum++;
  212. X#endif
  213. X        artopen(art);        /* rewind article in case interp */
  214. X                    /* forced a header parse */
  215. X        }
  216. X        else {
  217. X        ART_NUM i;
  218. X
  219. X#ifdef USETHREADS
  220. X        if (ThreadedGroup) {
  221. X            int sel, unseen;
  222. X
  223. X            sel = curr_p_art && (selected_roots[curr_p_art->root] & 1);
  224. X            unseen = !was_read(art);
  225. X            sprintf(art_buf,"%s%s #%ld",ngname,moderated,(long)art);
  226. X            if (selected_root_cnt) {
  227. X            i = selected_count - (unseen && sel);
  228. X            sprintf(art_buf+strlen(art_buf)," (%ld + %ld more)",
  229. X                (long)i,(long)toread[ng] - selected_count
  230. X                    - unthreaded - (!sel && unseen));
  231. X            }
  232. X            else if ((i = (ART_NUM)(toread[ng]-unthreaded-unseen)) != 0)
  233. X            sprintf(art_buf+strlen(art_buf)," (%ld more)",(long)i);
  234. X            linenum += tree_puts(art_buf,linenum+topline,0);
  235. X        }
  236. X        else
  237. X#endif
  238. X        {
  239. X#ifdef CLEAREOL
  240. X            maybe_eol();    
  241. X#endif /* CLEAREOL */
  242. X            printf("Article %ld",(long)art);
  243. X            i = (ART_NUM)(toread[ng] - 1 + was_read(art));
  244. X#ifdef DELAYMARK
  245. X            if (i || dmcount) {
  246. X            printf(" (%ld more",(long)i);
  247. X            if (dmcount)
  248. X                printf(" + %ld Marked to return",(long)dmcount);
  249. X            putchar(')');
  250. X            }
  251. X#else
  252. X            if (i)
  253. X            printf(" (%ld more)",(long)i);
  254. X#endif
  255. X            if (htype[NGS_LINE].ht_flags & HT_HIDE)
  256. X            printf(" in %s", ngname);
  257. X            fputs(moderated,stdout);
  258. X            fputs(":\n",stdout) FLUSH;
  259. X            linenum++;
  260. X        }
  261. X        }
  262. X        start_header(art);
  263. X        forcelast = FALSE;        /* we will have our day in court */
  264. X        restart = Nullch;
  265. X        artline = 0;        /* start counting lines */
  266. X        artpos = 0;
  267. X        vwtary(artline,artpos);    /* remember pos in file */
  268. X    }
  269. X    for (;                /* linenum already set */
  270. X      in_header || (
  271. X#ifdef INNERSEARCH
  272. X      innersearch ? innermore() :
  273. X#endif
  274. X      linenum<(firstpage?initlines:(special?slines:LINES)) );
  275. X      linenum++) {        /* for each line on page */
  276. X        if (int_count) {    /* exit via interrupt? */
  277. X        putchar('\n') FLUSH;    /* get to left margin */
  278. X        int_count = 0;    /* reset interrupt count */
  279. X        mode = oldmode;
  280. X        special = FALSE;
  281. X        return DA_NORM;    /* skip out of loops */
  282. X        }
  283. X        if (restart) {        /* did not finish last line? */
  284. X        bufptr = restart;    /* then start again here */
  285. X        restart = Nullch;    /* and reset the flag */
  286. X        }
  287. X        else {            /* not a restart */
  288. X        if (fgets(art_buf,LBUFLEN,artfp)==Nullch) {
  289. X                    /* if all done */
  290. X            mode = oldmode;
  291. X            special = FALSE;
  292. X            return DA_NORM;    /* skip out of loops */
  293. X        }
  294. X        bufptr = art_buf;    /* so start at beginning */
  295. X        art_buf[LBUFLEN-1] = '\0';
  296. X                    /* make sure string ends */
  297. X        }
  298. X        blinebeg = bufptr;    /* remember where we began */
  299. X        alinebeg = artpos;    /* both in buffer and file */
  300. X        if (in_header && bufptr == art_buf) {
  301. X        hide_this_line =
  302. X            parseline(art_buf,do_hiding,hide_this_line);
  303. X#ifdef USETHREADS
  304. X        if (!in_header) {
  305. X            linenum += finish_tree(linenum+topline);
  306. X        }
  307. X#endif
  308. X        } else if (notesfiles && do_hiding &&
  309. X          bufptr == art_buf && *art_buf == '#' &&
  310. X          isupper(art_buf[1]) && art_buf[2] == ':' ) {
  311. X        fgets(art_buf,sizeof(art_buf),artfp);
  312. X        if (index(art_buf,'!') != Nullch)
  313. X            fgets(art_buf,sizeof(art_buf),artfp);
  314. X        htype[PAST_HEADER].ht_minpos = ftell(artfp);
  315. X                    /* exclude notesfiles droppings */
  316. X        hide_this_line = TRUE;    /* and do not print either */
  317. X        notesfiles = FALSE;
  318. X        }
  319. X#ifdef CUSTOMLINES
  320. X        if (hideline && bufptr == art_buf &&
  321. X          execute(&hide_compex,art_buf) )
  322. X        hide_this_line = TRUE;
  323. X#endif
  324. X        if (in_header && htype[in_header].ht_flags & HT_MAGIC) {
  325. X        if (in_header == NGS_LINE) {
  326. X            hide_this_line = (index(art_buf,',') == Nullch);
  327. X        }
  328. X        else if (in_header == EXPIR_LINE) {
  329. X            if (!(htype[EXPIR_LINE].ht_flags & HT_HIDE))
  330. X            hide_this_line = (strlen(art_buf) < 10);
  331. X        }
  332. X        else if (in_header == FROM_LINE) {
  333. X            if (do_hiding && (s = index(art_buf+6,'(')) != Nullch) {
  334. X            strcpy(art_buf+6,s+1);
  335. X            if((s = rindex(art_buf+6,')')) != Nullch)
  336. X                *s = '\0';
  337. X            }
  338. X        }
  339. X#ifdef USETHREADS
  340. X        else if (in_header == DATE_LINE && curr_p_art && do_hiding) {
  341. X            strcpy(art_buf+6,ctime(&curr_p_art->date));
  342. X        }
  343. X#endif
  344. X        }
  345. X        if (in_header == SUBJ_LINE &&
  346. X        htype[SUBJ_LINE].ht_flags & HT_MAGIC) {
  347. X                /* is this the subject? */
  348. X        int length;
  349. X
  350. X        length = strlen(art_buf)-1;
  351. X        artline++;
  352. X        art_buf[length] = '\0';        /* wipe out newline */
  353. X#ifdef NOFIREWORKS
  354. X        no_ulfire();
  355. X#endif
  356. X        notesfiles =
  357. X            (instr(&art_buf[length-10]," - (nf") != Nullch);
  358. X#ifdef USETHREADS
  359. X        /* tree_puts(, ,1) underlines subject */
  360. X        linenum += tree_puts(art_buf,linenum+topline,1)-1;
  361. X#else
  362. X        if (oldsubject) {
  363. X            length += 7;
  364. X            fputs("(SAME) ",stdout);
  365. X            oldsubject = FALSE;
  366. X        }
  367. X        if (length+UG > COLS) {        /* rarely true */
  368. X            linenum++;
  369. X            vwtary(artline,vrdary(artline-1)+COLS);
  370. X            artline++;
  371. X        }
  372. X        s = art_buf + 8;
  373. X        *s++ = '\0';    /* make into 2 strings */
  374. X#ifdef CLEAREOL
  375. X        maybe_eol();    
  376. X#endif /* CLEAREOL */
  377. X        fputs(art_buf,stdout) FLUSH;
  378. X                /* print up through : */
  379. X        if (!UG)
  380. X            putchar(' ');
  381. X        underprint(s);    /* print subject underlined */
  382. X        putchar('\n') FLUSH;    /* and finish the line */
  383. X#endif
  384. X        }
  385. X        else if (hide_this_line && do_hiding) {
  386. X                    /* do not print line? */
  387. X        linenum--;        /* compensate for linenum++ */
  388. X        if (!in_header)
  389. X            hide_this_line = FALSE;
  390. X        }
  391. X#ifdef USETHREADS
  392. X        else if (in_header) {
  393. X        artline++;
  394. X        linenum += tree_puts(art_buf,linenum+topline,0)-1;
  395. X        }
  396. X#endif
  397. X        else {            /* just a normal line */
  398. X        if (highlight==artline) {    /* this line to be highlit? */
  399. X            if (marking == STANDOUT) {
  400. X#ifdef NOFIREWORKS
  401. X            if (erase_screen)
  402. X                no_sofire();
  403. X#endif
  404. X            standout();
  405. X            }
  406. X            else {
  407. X#ifdef NOFIREWORKS
  408. X            if (erase_screen)
  409. X                no_ulfire();
  410. X#endif
  411. X            underline();
  412. X            }
  413. X            if (*bufptr == '\n')
  414. X            putchar(' ');
  415. X        }
  416. X#ifdef INNERSEARCH
  417. X        outputok = !hide_everything;
  418. X                    /* get it into register, hopefully */
  419. X#endif
  420. X#ifdef CLEAREOL
  421. X#ifdef INNERSEARCH
  422. X        if (outputok)
  423. X#endif
  424. X        maybe_eol();    
  425. X#endif /* CLEAREOL */
  426. X#ifdef CUSTOMLINES
  427. X        if (pagestop && bufptr == art_buf && 
  428. X          execute(&page_compex,art_buf) )
  429. X            linenum = 32700;
  430. X#endif
  431. X        for (outpos = 0; outpos < COLS; ) {
  432. X                    /* while line has room */
  433. X            if (*(unsigned char *)bufptr >= ' ') { /* normal char? */
  434. X#ifdef ULSMARTS
  435. X            if (*bufptr == '_') {
  436. X                if (bufptr[1] == '\b') {
  437. X                if (!under_lining && highlight!=artline
  438. X#ifdef INNERSEARCH
  439. X                    && outputok
  440. X#endif
  441. X                    ) {
  442. X                    under_lining++;
  443. X                    if (UG) {
  444. X                    if (bufptr != buf &&
  445. X                      bufptr[-1] == ' ') {
  446. X                        outpos--;
  447. X                        backspace();
  448. X                    }
  449. X                    }
  450. X                    underline();
  451. X                }
  452. X                bufptr += 2;
  453. X                }
  454. X            }
  455. X            else {
  456. X                if (under_lining) {
  457. X                under_lining = 0;
  458. X                un_underline();
  459. X                if (UG) {
  460. X                    if (*bufptr == ' ')
  461. X                    goto skip_put;
  462. X                    outpos++;
  463. X                }
  464. X                }
  465. X            }
  466. X#endif
  467. X#ifdef INNERSEARCH
  468. X            if (outputok)
  469. X#endif
  470. X            {
  471. X#ifdef ROTATION
  472. X                if (rotate && !in_header
  473. X                  && isalpha(*bufptr)) {
  474. X                if ((*bufptr & 31) <= 13)
  475. X                    putchar(*bufptr+13);
  476. X                else
  477. X                    putchar(*bufptr-13);
  478. X                }
  479. X                else
  480. X#endif
  481. X                putchar(*bufptr);
  482. X            }
  483. X            if (*UC && ((highlight==artline && marking == 1)
  484. X#ifdef ULSMARTS
  485. X                || under_lining
  486. X#endif
  487. X                )) {
  488. X                backspace();
  489. X                underchar();
  490. X            }
  491. X            skip_put:
  492. X            bufptr++;
  493. X            outpos++;
  494. X            }
  495. X            else if (*bufptr == '\n' || !*bufptr) {
  496. X                            /* newline? */
  497. X#ifdef ULSMARTS
  498. X            if (under_lining) {
  499. X                under_lining = 0;
  500. X                un_underline();
  501. X            }
  502. X#endif
  503. X#ifdef DEBUGGING
  504. X            if (debug & DEB_INNERSRCH && outpos < COLS - 6) {
  505. X                standout();
  506. X                printf("%4d",artline); 
  507. X                un_standout();
  508. X            }
  509. X#endif
  510. X#ifdef INNERSEARCH
  511. X            if (outputok)
  512. X#endif
  513. X                putchar('\n') FLUSH;
  514. X            restart = 0;
  515. X            outpos = 1000;    /* signal normal \n */
  516. X            }
  517. X            else if (*bufptr == '\t') {    /* tab? */
  518. X#ifdef INNERSEARCH
  519. X            if (outputok)
  520. X#endif
  521. X                putchar(*bufptr);
  522. X            bufptr++;
  523. X            outpos += 8 - outpos % 8;
  524. X            }
  525. X            else if (*bufptr == '\f') {    /* form feed? */
  526. X#ifdef INNERSEARCH
  527. X            if (outputok)
  528. X#endif
  529. X                fputs("^L",stdout);
  530. X            if (bufptr == blinebeg && highlight != artline)
  531. X                linenum = 32700;
  532. X                /* how is that for a magic number? */
  533. X            bufptr++;
  534. X            outpos += 2;
  535. X            }
  536. X            else {        /* other control char */
  537. X#ifdef INNERSEARCH
  538. X            if (outputok)
  539. X#endif
  540. X            {
  541. X                putchar('^');
  542. X                if (highlight == artline && *UC && marking == 1) {
  543. X                backspace();
  544. X                underchar();
  545. X                putchar(*bufptr+64);
  546. X                backspace();
  547. X                underchar();
  548. X                }
  549. X                else
  550. X                putchar(*bufptr+64);
  551. X            }
  552. X            bufptr++;
  553. X            outpos += 2;
  554. X            }
  555. X            
  556. X        } /* end of column loop */
  557. X
  558. X        if (outpos < 1000) {/* did line overflow? */
  559. X            restart = bufptr;
  560. X                    /* restart here next time */
  561. X            if (AM) {    /* automatic margins on tty? */
  562. X            if (!XN && *bufptr == '\n')
  563. X                    /* need we simulate XN? */
  564. X                restart = 0;
  565. X                    /* skip the newline */
  566. X            }
  567. X            else {        /* cursor just hangs there */
  568. X#ifdef INNERSEARCH
  569. X            if (outputok)
  570. X#endif
  571. X                putchar('\n') FLUSH;
  572. X                    /* so move it down ourselves */
  573. X            if (*bufptr == '\n')
  574. X                restart = 0;
  575. X                    /* simulate XN if need be */
  576. X            }
  577. X#ifdef CLEAREOL
  578. X#ifdef INNERSEARCH
  579. X            if (outputok) 
  580. X#endif
  581. X             {
  582. X               /* force movement onto the new line so CE will work */
  583. X               putchar(' ');
  584. X               backspace();
  585. X               maybe_eol();
  586. X             }
  587. X#endif /* CLEAREOL */
  588. X        }
  589. X
  590. X        /* handle normal end of output line formalities */
  591. X
  592. X        if (highlight == artline) {
  593. X                    /* were we highlighting line? */
  594. X            if (marking == STANDOUT)
  595. X            un_standout();
  596. X            else
  597. X            un_underline();
  598. X            highlight = -1;    /* no more we are */
  599. X        }
  600. X        artline++;    /* count the line just printed */
  601. X        if (artline - LINES + 1 > topline)
  602. X                /* did we just scroll top line off? */
  603. X            topline = artline - LINES + 1;
  604. X                /* then recompute top line # */
  605. X        }
  606. X
  607. X        /* determine actual position in file */
  608. X
  609. X        if (restart)    /* stranded somewhere in the buffer? */
  610. X        artpos += restart - blinebeg;
  611. X                /* just calculate position */
  612. X        else        /* no, ftell will do */
  613. X        artpos = ftell(artfp);
  614. X                /* so do ftell */
  615. X        vwtary(artline,artpos);    /* remember pos in file */
  616. X    } /* end of line loop */
  617. X
  618. X#ifdef INNERSEARCH
  619. X    innersearch = 0;
  620. X    if (hide_everything) {
  621. X        hide_everything = FALSE;
  622. X        *buf = Ctl('l');
  623. X        goto fake_command;
  624. X    }
  625. X#endif
  626. X    if (linenum >= 32700)/* did last line have formfeed? */
  627. X        vwtary(artline-1,-vrdary(artline-1));
  628. X                /* remember by negating pos in file */
  629. X
  630. X    special = FALSE;    /* end of page, so reset page length */
  631. X    firstpage = FALSE;    /* and say it is not 1st time thru */
  632. X
  633. X    /* extra loop bombout */
  634. X
  635. X    if (artpos == artsize) {/* did we just now reach EOF? */
  636. X        mode = oldmode;
  637. X        return DA_NORM;    /* avoid --MORE--(100%) */
  638. X    }
  639. X
  640. X/* not done with this article, so pretend we are a pager */
  641. X
  642. Xreask_pager:            
  643. X    unflush_output();    /* disable any ^O in effect */
  644. X    standout();        /* enter standout mode */
  645. X    printf("--MORE--(%ld%%)",(long)(artpos*100/artsize));
  646. X    un_standout();    /* leave standout mode */
  647. X#ifdef CLEAREOL
  648. X     maybe_eol();
  649. X#endif
  650. X    fflush(stdout);
  651. X/* reinp_pager:                 /* unused, commented for lint */
  652. X    eat_typeahead();
  653. X#ifdef DEBUGGING
  654. X    if (debug & DEB_CHECKPOINTING) {
  655. X        printf("(%d %d %d)",checkcount,linenum,artline);
  656. X        fflush(stdout);
  657. X    }
  658. X#endif
  659. X    if (checkcount >= docheckwhen &&
  660. X      linenum == LINES &&
  661. X      (artline > 40 || checkcount >= docheckwhen+10) ) {
  662. X                /* while he is reading a whole page */
  663. X                /* in an article he is interested in */
  664. X        checkcount = 0;
  665. X        checkpoint_rc();    /* update .newsrc */
  666. X    }
  667. X    collect_subjects();        /* loads subject cache until */
  668. X                    /* input is pending */
  669. X    mode = 'p';
  670. X    getcmd(buf);
  671. X    if (errno) {
  672. X        if (LINES < 100 && !int_count)
  673. X        *buf = '\f';/* on CONT fake up refresh */
  674. X        else {
  675. X        *buf = 'q';    /* on INTR or paper just quit */
  676. X        }
  677. X    }
  678. X    carriage_return();
  679. X#ifndef CLEAREOL
  680. X    erase_eol();    /* and erase the prompt */
  681. X#else
  682. X    if (erase_screen && can_home_clear)    
  683. X        clear_rest();
  684. X    else
  685. X        erase_eol();    /* and erase the prompt */
  686. X#endif /* CLEAREOL */
  687. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  688. X    fflush(stdout);
  689. X
  690. X    fake_command:        /* used by innersearch */
  691. X
  692. X    /* parse and process pager command */
  693. X
  694. X    switch (page_switch()) {
  695. X    case PS_ASK:    /* reprompt "--MORE--..." */
  696. X        goto reask_pager;
  697. X    case PS_RAISE:    /* reparse on article level */
  698. X        mode = oldmode;
  699. X        return DA_RAISE;
  700. X    case PS_TOEND:    /* fast pager loop exit */
  701. X        mode = oldmode;
  702. X        return DA_TOEND;
  703. X    case PS_NORM:    /* display more article */
  704. X        break;
  705. X    }
  706. X    } /* end of page loop */
  707. X}
  708. X
  709. X/* process pager commands */
  710. X
  711. Xint
  712. Xpage_switch()
  713. X{
  714. X    register char *s;
  715. X    
  716. X    switch (*buf) {
  717. X    case 'd':
  718. X    case Ctl('d'):    /* half page */
  719. X    special = TRUE;
  720. X    slines = LINES / 2 + 1;
  721. X    if (marking && *blinebeg != '\f'
  722. X#ifdef CUSTOMLINES
  723. X      && (!pagestop || blinebeg != art_buf ||
  724. X          !execute(&page_compex,blinebeg))
  725. X#endif
  726. X      ) {
  727. X        up_line();
  728. X        highlight = --artline;
  729. X        restart = blinebeg;
  730. X        artpos = alinebeg;
  731. X    }
  732. X    return PS_NORM;
  733. X    case '!':            /* shell escape */
  734. X    escapade();
  735. X    return PS_ASK;
  736. X#ifdef INNERSEARCH
  737. X    case Ctl('i'):
  738. X    gline = 3;
  739. X    sprintf(cmd_buf,"^[^%c]",*blinebeg);
  740. X    compile(&gcompex,cmd_buf,TRUE,TRUE);
  741. X    goto caseG;
  742. X    case Ctl('g'):
  743. X    gline = 3;
  744. X    compile(&gcompex,"^Subject:",TRUE,TRUE);
  745. X    goto caseG;
  746. X    case 'g':        /* in-article search */
  747. X    if (!finish_command(FALSE))/* get rest of command */
  748. X        return PS_ASK;
  749. X    s = buf+1;
  750. X    if (isspace(*s))
  751. X        s++;
  752. X    if ((s = compile(&gcompex,s,TRUE,TRUE)) != Nullch) {
  753. X                /* compile regular expression */
  754. X        printf("\n%s\n",s) FLUSH;
  755. X        return PS_ASK;
  756. X    }
  757. X    carriage_return();
  758. X    erase_eol();    /* erase the prompt */
  759. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  760. X    /* FALL THROUGH */
  761. X    caseG:
  762. X    case 'G': {
  763. X    /* ART_LINE lines_to_skip = 0; */
  764. X    ART_POS start_where;
  765. X
  766. X    if (gline < 0 || gline > LINES-2)
  767. X        gline = LINES-2;
  768. X#ifdef DEBUGGING
  769. X    if (debug & DEB_INNERSRCH)
  770. X        printf("Start here? %d  >=? %d\n",topline + gline + 1,artline)
  771. X          FLUSH;
  772. X#endif
  773. X    if (*buf == Ctl('i') || topline+gline+1 >= artline)
  774. X        start_where = artpos;
  775. X            /* in case we had a line wrap */
  776. X    else {
  777. X        start_where = vrdary(topline+gline+1);
  778. X        if (start_where < 0)
  779. X        start_where = -start_where;
  780. X    }
  781. X    if (start_where < htype[PAST_HEADER].ht_minpos)
  782. X        start_where = htype[PAST_HEADER].ht_minpos;
  783. X    fseek(artfp,(long)start_where,0);
  784. X    innersearch = 0; /* assume not found */
  785. X    while (fgets(buf, sizeof buf, artfp) != Nullch) {
  786. X        /* lines_to_skip++;         NOT USED NOW */
  787. X#ifdef DEBUGGING
  788. X        if (debug & DEB_INNERSRCH)
  789. X        printf("Test %s",buf) FLUSH;
  790. X#endif
  791. X        if (execute(&gcompex,buf) != Nullch) {
  792. X        innersearch = ftell(artfp);
  793. X        break;
  794. X        }
  795. X    }
  796. X    if (!innersearch) {
  797. X        fseek(artfp,artpos,0);
  798. X        fputs("(Not found)",stdout) FLUSH;
  799. X        return PS_ASK;
  800. X    }
  801. X#ifdef DEBUGGING
  802. X    if (debug & DEB_INNERSRCH)
  803. X        printf("On page? %ld <=? %ld\n",(long)innersearch,(long)artpos)
  804. X          FLUSH;
  805. X#endif
  806. X    if (innersearch <= artpos) {    /* already on page? */
  807. X        if (innersearch < artpos) {
  808. X        artline = topline+1;
  809. X        while (vrdary(artline) < innersearch)
  810. X            artline++;
  811. X        }
  812. X        highlight = artline - 1;
  813. X#ifdef DEBUGGING
  814. X        if (debug & DEB_INNERSRCH)
  815. X        printf("@ %d\n",highlight) FLUSH;
  816. X#endif
  817. X        topline = highlight - gline;
  818. X        if (topline < -1)
  819. X        topline = -1;
  820. X        *buf = '\f';        /* fake up a refresh */
  821. X        innersearch = 0;
  822. X        return page_switch();
  823. X    }
  824. X    else {                /* who knows how many lines it is? */
  825. X        do_fseek = TRUE;
  826. X        hide_everything = TRUE;
  827. X    }
  828. X    return PS_NORM;
  829. X    }
  830. X#else
  831. X    case 'g': case 'G': case Ctl('g'):
  832. X    notincl("g");
  833. X    return PS_ASK;
  834. X#endif
  835. X    case '\n':        /* one line */
  836. X    special = TRUE;
  837. X    slines = 2;
  838. X    return PS_NORM;
  839. X#ifdef ROTATION
  840. X    case 'X':
  841. X    rotate = !rotate;
  842. X    /* FALL THROUGH */
  843. X#endif
  844. X    case 'l':
  845. X    case '\f':        /* refresh screen */
  846. X#ifdef DEBUGGING
  847. X    if (debug & DEB_INNERSRCH) {
  848. X        printf("Topline = %d",topline) FLUSH;
  849. X        gets(buf);
  850. X    }
  851. X#endif
  852. X    clear();
  853. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  854. X    do_fseek = TRUE;
  855. X    artline = topline;
  856. X    if (artline < 0)
  857. X        artline = 0;
  858. X    firstpage = (topline < 0);
  859. X    return PS_NORM;
  860. X    case 'b':
  861. X    case '\b':
  862. X    case Ctl('b'): {    /* back up a page */
  863. X    ART_LINE target;
  864. X
  865. X#ifndef CLEAREOL
  866. X    clear();
  867. X#else
  868. X    if (can_home_clear)    /* if we can home do it */
  869. X        home_cursor();
  870. X    else
  871. X        clear();
  872. X
  873. X#endif /* CLEAREOL */
  874. X    carriage_return();    /* Resets kernel's tab column counter to 0 */
  875. X    do_fseek = TRUE;    /* reposition article file */
  876. X    target = topline - (LINES - 2);
  877. X    artline = topline;
  878. X    if (artline >= 0) do {
  879. X        artline--;
  880. X    } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
  881. X    topline = artline;
  882. X            /* remember top line of screen */
  883. X            /*  (line # within article file) */
  884. X    if (artline < 0)
  885. X        artline = 0;
  886. X    firstpage = (topline < 0);
  887. X    return PS_NORM;
  888. X    }
  889. X    case 'h': {        /* help */
  890. X    int cmd;
  891. X
  892. X    if ((cmd = help_page()) > 0)
  893. X        pushchar(cmd);
  894. X    return PS_ASK;
  895. X    }
  896. X#ifdef USETHREADS
  897. X    case 't':        /* output thread data */
  898. X    page_line = 1;
  899. X    p_art = curr_p_art;
  900. X    entire_tree();
  901. X    return PS_ASK;
  902. X#endif
  903. X    case '\177':
  904. X    case '\0':        /* treat del,break as 'n' */
  905. X    *buf = 'n';
  906. X    /* FALL THROUGH */
  907. X    case 'k':    case 'K':
  908. X#ifdef USETHREADS
  909. X    case 'T':    case 'J':
  910. X#endif
  911. X    case 'n':    case 'N':    case Ctl('n'):
  912. X    case 's':    case 'S':
  913. X    case 'e':
  914. X    case 'u':
  915. X    case 'w':    case 'W':
  916. X    case '|':
  917. X    mark_as_read();        /* mark article as read */
  918. X    /* FALL THROUGH */
  919. X#ifdef USETHREADS
  920. X    case 'U':    case ',':
  921. X    case '<':    case '>':
  922. X    case '[':    case ']':
  923. X    case '{':    case '}':
  924. X    case '+':   case ':':
  925. X#endif
  926. X    case '#':
  927. X    case '$':
  928. X    case '&':
  929. X    case '-':
  930. X    case '.':
  931. X    case '/':
  932. X    case '1': case '2': case '3': case '4': case '5':
  933. X    case '6': case '7': case '8': case '9':
  934. X    case '=':
  935. X    case '?':
  936. X    case 'c':    case 'C':    
  937. X#ifdef DEBUGGING
  938. X    case 'D':
  939. X#endif
  940. X    case 'E':
  941. X    case 'f':    case 'F':    
  942. X    case 'j':
  943. X                case Ctl('k'):
  944. X    case 'm':    case 'M':    
  945. X    case 'p':    case 'P':    case Ctl('p'):    
  946. X        case 'Q':
  947. X    case 'r':    case 'R':    case Ctl('r'):
  948. X    case 'v':
  949. X        case 'Y':
  950. X#ifndef ROTATION
  951. X    case 'x':    case 'X':
  952. X#endif
  953. X    case Ctl('x'):
  954. X    case '^':
  955. X
  956. X#ifdef ROTATION
  957. X    rotate = FALSE;
  958. X#endif
  959. X    reread = FALSE;
  960. X    do_hiding = TRUE;
  961. X    if (index("nNpP\016\018",*buf) == Nullch &&
  962. X      index("wWsSe:!&|/?123456789.",*buf) != Nullch) {
  963. X        setdfltcmd();
  964. X        standout();        /* enter standout mode */
  965. X        printf(prompt,mailcall,dfltcmd);
  966. X                /* print prompt, whatever it is */
  967. X        un_standout();    /* leave standout mode */
  968. X        putchar(' ');
  969. X        fflush(stdout);
  970. X    }
  971. X    return PS_RAISE;    /* and pretend we were at end */
  972. X#ifdef ROTATION
  973. X    case 'x':
  974. X    rotate = TRUE;
  975. X    /* FALL THROUGH */
  976. X#endif
  977. X    case 'y':
  978. X    case Ctl('v'):
  979. X                    /* Leaving it undocumented in case */
  980. X                    /* I want to steal the key--LAW */
  981. X    case ' ':    /* continue current article */
  982. X    if (erase_screen) {    /* -e? */
  983. X#ifndef CLEAREOL
  984. X        clear();        /* clear screen */
  985. X#else
  986. X        if (can_home_clear)    /* if we can home do it */
  987. X        home_cursor();
  988. X        else
  989. X        clear();    /* else clear screen */
  990. X
  991. X#endif /* CLEAREOL */
  992. X        carriage_return();    /* Resets kernel's tab column counter to 0 */
  993. X        fflush(stdout);
  994. X
  995. X        if (*blinebeg != '\f'
  996. X#ifdef CUSTOMLINES
  997. X          && (!pagestop || blinebeg != art_buf ||
  998. X              !execute(&page_compex,blinebeg))
  999. X#endif
  1000. X          ) {
  1001. X        restart = blinebeg;
  1002. X        artline--;     /* restart this line */
  1003. X        artpos = alinebeg;
  1004. X        if (marking)    /* and mark repeated line */
  1005. X            highlight = artline;
  1006. X        }
  1007. X        topline = artline;
  1008. X            /* and remember top line of screen */
  1009. X            /*  (line # within article file) */
  1010. X    }
  1011. X    else if (marking && *blinebeg != '\f'
  1012. X#ifdef CUSTOMLINES
  1013. X      && (!pagestop || blinebeg != art_buf ||
  1014. X          !execute(&page_compex,blinebeg))
  1015. X#endif
  1016. X      ) {
  1017. X                /* are we marking repeats? */
  1018. X        up_line();        /* go up one line */
  1019. X        highlight = --artline;/* and get ready to highlight */
  1020. X        restart = blinebeg;    /*   the old line */
  1021. X        artpos = alinebeg;
  1022. X    }
  1023. X    return PS_NORM;
  1024. X    case 'q':    /* quit this article? */
  1025. X    do_hiding = TRUE;
  1026. X    return PS_TOEND;
  1027. X    default:
  1028. X    fputs(hforhelp,stdout) FLUSH;
  1029. X    settle_down();
  1030. X    return PS_ASK;
  1031. X    }
  1032. X}
  1033. X
  1034. X#ifdef INNERSEARCH
  1035. Xbool
  1036. Xinnermore()
  1037. X{
  1038. X    if (artpos < innersearch) {        /* not even on page yet? */
  1039. X#ifdef DEBUGGING
  1040. X    if (debug & DEB_INNERSRCH)
  1041. X        printf("Not on page %ld < %ld\n",(long)artpos,(long)innersearch)
  1042. X          FLUSH;
  1043. X#endif
  1044. X    return TRUE;
  1045. X    }
  1046. X    if (artpos == innersearch) {    /* just got onto page? */
  1047. X    isrchline = artline;        /* remember first line after */
  1048. X    highlight = artline - 1;
  1049. X#ifdef DEBUGGING
  1050. X    if (debug & DEB_INNERSRCH)
  1051. X        printf("There it is %ld = %ld, %d @ %d\n",(long)artpos,
  1052. X        (long)innersearch,hide_everything,highlight) FLUSH;
  1053. X#endif
  1054. X    if (hide_everything) {        /* forced refresh? */
  1055. X        topline = highlight - gline;
  1056. X        if (topline < -1)
  1057. X        topline = -1;
  1058. X        return FALSE;        /* let refresh do it all */
  1059. X    }
  1060. X    }
  1061. X#ifdef DEBUGGING
  1062. X    if (debug & DEB_INNERSRCH)
  1063. X    printf("Not far enough? %d <? %d + %d\n",artline,isrchline,gline)
  1064. X      FLUSH;
  1065. X#endif
  1066. X    if (artline < isrchline + gline) {
  1067. X    return TRUE;
  1068. X    }
  1069. X    return FALSE;
  1070. X}
  1071. X#endif
  1072. END_OF_FILE
  1073.   if test 26201 -ne `wc -c <'art.c'`; then
  1074.     echo shar: \"'art.c'\" unpacked with wrong size!
  1075.   fi
  1076.   # end of 'art.c'
  1077. fi
  1078. if test -f 'ng.c' -a "${1}" != "-c" ; then 
  1079.   echo shar: Will not clobber existing file \"'ng.c'\"
  1080. else
  1081.   echo shar: Extracting \"'ng.c'\" \(34884 characters\)
  1082.   sed "s/^X//" >'ng.c' <<'END_OF_FILE'
  1083. X/* $Header: ng.c,v 4.3.3.3 91/01/16 03:18:16 davison Trn $
  1084. X *
  1085. X * $Log:    ng.c,v $
  1086. X * Revision 4.3.3.3  91/01/16  03:18:16  davison
  1087. X * Integrated rn patches 48-54.  Fixed in_char/verify interaction.
  1088. X * 
  1089. X * Revision 4.3.3.2  90/08/20  16:03:45  davison
  1090. X * Fixed bug in backpage code.
  1091. X * 
  1092. X * Revision 4.3.3.1  90/07/21  20:27:17  davison
  1093. X * Initial Trn Release
  1094. X * 
  1095. X * Revision 4.3.2.9  91/01/05  14:56:47  sob
  1096. X * Removed bogus "fast skip" for NNTP.
  1097. X *
  1098. X * Revision 4.3.2.8  90/11/22  16:14:17  sob
  1099. X * Added changes to accomodate picky C preprocessors
  1100. X * 
  1101. X * Revision 4.3.2.7  90/04/21  14:44:23  sob
  1102. X * Revised previous patch insure that it does not decrement below zero.
  1103. X * 
  1104. X * Revision 4.3.2.6  90/03/22  23:04:49  sob
  1105. X * Fixes provided by Wayne Davison <drivax!davison>
  1106. X * 
  1107. X * Revision 4.3.2.5  89/12/09  01:18:42  sob
  1108. X * Fixed a bad call to nntpopen().
  1109. X * 
  1110. X * Revision 4.3.2.4  89/11/28  01:51:20  sob
  1111. X * Removed redundant #include directive.
  1112. X * 
  1113. X * Revision 4.3.2.3  89/11/27  01:31:03  sob
  1114. X * Altered NNTP code per ideas suggested by Bela Lubkin
  1115. X * <filbo@gorn.santa-cruz.ca.us>
  1116. X * 
  1117. X * Revision 4.3.2.2  89/11/26  22:53:35  sob
  1118. X * Add new patches to make RRN be faster.
  1119. X * 
  1120. X * Revision 4.3.2.1  89/11/06  00:54:27  sob
  1121. X * Added RRN support from NNTP 1.5
  1122. X * 
  1123. X * Revision 4.3.1.6  85/09/10  11:03:42  lwall
  1124. X * Improved %m in in_char().
  1125. X * 
  1126. X * Revision 4.3.1.5  85/09/05  12:34:37  lwall
  1127. X * Catchup command could make unread article count too big.
  1128. X * 
  1129. X * Revision 4.3.1.4  85/07/23  18:19:46  lwall
  1130. X * Added MAILCALL environment variable.
  1131. X * 
  1132. X * Revision 4.3.1.3  85/05/16  16:48:09  lwall
  1133. X * Fixed unsubsubscribe.
  1134. X * 
  1135. X * Revision 4.3.1.2  85/05/13  09:29:28  lwall
  1136. X * Added CUSTOMLINES option.
  1137. X * 
  1138. X * Revision 4.3.1.1  85/05/10  11:36:00  lwall
  1139. X * Branch for patches.
  1140. X * 
  1141. X * Revision 4.3  85/05/01  11:43:43  lwall
  1142. X * Baseline for release with 4.3bsd.
  1143. X * 
  1144. X */
  1145. X
  1146. X#include "EXTERN.h"
  1147. X#include "common.h"
  1148. X#include "rn.h"
  1149. X#include "term.h"
  1150. X#include "final.h"
  1151. X#include "util.h"
  1152. X#include "artsrch.h"
  1153. X#include "cheat.h"
  1154. X#include "help.h"
  1155. X#include "kfile.h"
  1156. X#include "rcstuff.h"
  1157. X#include "head.h"
  1158. X#include "bits.h"
  1159. X#include "art.h"
  1160. X#include "artio.h"
  1161. X#include "ngstuff.h"
  1162. X#include "intrp.h"
  1163. X#include "respond.h"
  1164. X#include "ngdata.h"
  1165. X#include "backpage.h"
  1166. X#include "rcln.h"
  1167. X#include "last.h"
  1168. X#include "search.h"
  1169. X#ifdef SERVER
  1170. X#include "server.h"
  1171. X#endif
  1172. X#ifdef USETHREADS
  1173. X#include "rthreads.h"
  1174. X#endif
  1175. X#include "uudecode.h"
  1176. X#include "INTERN.h"
  1177. X#include "ng.h"
  1178. X#include "artstate.h"            /* somebody has to do it */
  1179. X
  1180. X/* art_switch() return values */
  1181. X
  1182. X#define AS_NORM 0
  1183. X#define AS_INP 1
  1184. X#define AS_ASK 2
  1185. X#define AS_CLEAN 3
  1186. X
  1187. XART_NUM recent_art = -1;    /* previous article # for '-' command */
  1188. XART_NUM curr_art = -1;        /* current article # */
  1189. Xint exit_code = NG_NORM;
  1190. X
  1191. Xvoid
  1192. Xng_init()
  1193. X{
  1194. X
  1195. X#ifdef KILLFILES
  1196. X    open_kfile(KF_GLOBAL);
  1197. X#endif
  1198. X#ifdef CUSTOMLINES
  1199. X    init_compex(&hide_compex);
  1200. X    init_compex(&page_compex);
  1201. X#endif
  1202. X}
  1203. X
  1204. X/* do newsgroup on line ng with name ngname */
  1205. X
  1206. X/* assumes that we are chdir'ed to SPOOL, and assures that that is
  1207. X * still true upon return, but chdirs to SPOOL/ngname in between
  1208. X *
  1209. X * If you can understand this routine, you understand most of the program.
  1210. X * The basic structure is:
  1211. X *    for each desired article
  1212. X *        for each desired page
  1213. X *            for each line on page
  1214. X *                if we need another line from file
  1215. X *                    get it
  1216. X *                    if it's a header line
  1217. X *                        do special things
  1218. X *                for each column on page
  1219. X *                    put out a character
  1220. X *                end loop
  1221. X *            end loop
  1222. X *        end loop
  1223. X *    end loop
  1224. X *
  1225. X *    (Actually, the pager is in another routine.)
  1226. X *
  1227. X * The chief problem is deciding what is meant by "desired".  Most of
  1228. X * the messiness of this routine is due to the fact that people want
  1229. X * to do unstructured things all the time.  I have used a few judicious
  1230. X * goto's where I thought it improved readability.  The rest of the messiness
  1231. X * arises from trying to be both space and time efficient.  Have fun.
  1232. X */
  1233. X
  1234. Xint
  1235. Xdo_newsgroup(start_command)
  1236. Xchar *start_command;            /* command to fake up first */
  1237. X{
  1238. X#ifdef SERVER
  1239. X    char ser_line[256];
  1240. X    char artname[32];
  1241. X    static long our_pid=0;
  1242. X#endif /* SERVER */
  1243. X    char oldmode = mode;
  1244. X    register long i;            /* scratch */
  1245. X    int skipstate;            /* how many unavailable articles */
  1246. X                    /*   have we skipped already? */
  1247. X    
  1248. X    char *whatnext = "%sWhat next? [%s]";
  1249. X
  1250. X#ifdef SERVER
  1251. X    if (our_pid == 0)           /* Agreed, this is gross */
  1252. X        our_pid = getpid();
  1253. X#endif /* SERVER */
  1254. X
  1255. X#ifdef ARTSEARCH
  1256. X    srchahead = (scanon && ((ART_NUM)toread[ng]) >= scanon ? -1 : 0);
  1257. X                    /* did they say -S? */
  1258. X#endif
  1259. X    
  1260. X    mode = 'a';
  1261. X#ifdef USETHREADS
  1262. X    recent_p_art = curr_p_art = Nullart;
  1263. X#endif
  1264. X    recent_art = curr_art = -1;
  1265. X    exit_code = NG_NORM;
  1266. X
  1267. X#ifdef SERVER
  1268. X    sprintf(ser_line, "GROUP %s", ngname);
  1269. X    put_server(ser_line);
  1270. X    if (get_server(ser_line, sizeof(ser_line)) < 0) {
  1271. X    fprintf(stderr, "rrn: Unexpected close of server socket.\n");
  1272. X    finalize(1);
  1273. X    }
  1274. X    if (*ser_line != CHAR_OK) {
  1275. X    if (atoi(ser_line) != ERR_NOGROUP)
  1276. X        fprintf(stderr, "rrn: server response to GROUP %s:\n%s\n",
  1277. X            ngname, ser_line);
  1278. X    return (-1);
  1279. X    }
  1280. X#else /* not SERVER */
  1281. X    if (eaccess(ngdir,5)) {        /* directory read protected? */
  1282. X    if (eaccess(ngdir,0)) {
  1283. X#ifdef VERBOSE
  1284. X        IF(verbose)
  1285. X        printf("\nNewsgroup %s does not have a spool directory!\n",
  1286. X            ngname) FLUSH;
  1287. X        ELSE
  1288. X#endif
  1289. X#ifdef TERSE
  1290. X        printf("\nNo spool for %s!\n",ngname) FLUSH;
  1291. X#endif
  1292. X#ifdef CATCHUP
  1293. X        catch_up(ng);
  1294. X#endif
  1295. X        toread[ng] = TR_NONE;
  1296. X    }
  1297. X    else {
  1298. X#ifdef VERBOSE
  1299. X        IF(verbose)
  1300. X        printf("\nNewsgroup %s is not currently accessible.\n",
  1301. X            ngname) FLUSH;
  1302. X        ELSE
  1303. X#endif
  1304. X#ifdef TERSE
  1305. X        printf("\n%s not readable.\n",ngname) FLUSH;
  1306. X#endif
  1307. X        toread[ng] = TR_NONE;    /* make this newsgroup invisible */
  1308. X                    /* (temporarily) */
  1309. X    }
  1310. X    mode = oldmode;
  1311. X    return -1;
  1312. X    }
  1313. X
  1314. X    /* chdir to newsgroup subdirectory */
  1315. X
  1316. X    if (chdir(ngdir)) {
  1317. X    printf(nocd,ngdir) FLUSH;
  1318. X    mode = oldmode;
  1319. X    return -1;
  1320. X    }
  1321. X#endif /* SERVER */
  1322. X
  1323. X#ifdef CACHESUBJ
  1324. X    subj_list = Null(char **);        /* no subject list till needed */
  1325. X#endif
  1326. X    
  1327. X    /* initialize control bitmap */
  1328. X
  1329. X    if (initctl()) {
  1330. X    mode = oldmode;
  1331. X    return -1;
  1332. X    }
  1333. X
  1334. X    /* FROM HERE ON, RETURN THRU CLEANUP OR WE ARE SCREWED */
  1335. X
  1336. X    /* grab threaded data */
  1337. X
  1338. X#ifdef USETHREADS
  1339. X    if (ThreadedGroup && (ThreadedGroup = use_data(thread_name(ngname)))) {
  1340. X    /* check if thread file is newer than the active2 entry (this is
  1341. X    ** possible when mthreads is still running.) */
  1342. X    if (total.last > lastart) {
  1343. X        grow_ctl(total.last);    /* sets lastart */
  1344. X    }
  1345. X    else if (total.last < lastart) {
  1346. X        /* If the active2 entry is newer than the data file, something
  1347. X        ** bad is going on.  Forget using the thread data. */
  1348. X        unuse_data(0);
  1349. X        ThreadedGroup = FALSE;
  1350. X    }
  1351. X    }
  1352. X#endif
  1353. X
  1354. X    in_ng = TRUE;            /* tell the world we are here */
  1355. X    forcelast = TRUE;            /* if 0 unread, do not bomb out */
  1356. X
  1357. X    /* remember what newsgroup we were in for sake of posterity */
  1358. X
  1359. X    writelast();
  1360. X
  1361. X    /* see if there are any special searches to do */
  1362. X
  1363. X#ifdef KILLFILES
  1364. X    open_kfile(KF_LOCAL);
  1365. X#ifdef VERBOSE
  1366. X    IF(verbose)
  1367. X    kill_unwanted(firstart,"Looking for articles to kill...\n\n",TRUE);
  1368. X    ELSE
  1369. X#endif
  1370. X#ifdef TERSE
  1371. X    kill_unwanted(firstart,"Killing...\n\n",TRUE);
  1372. X#endif
  1373. X#endif
  1374. X#ifdef USETHREADS
  1375. X    first_art();
  1376. X#else
  1377. X    art=firstart;
  1378. X#endif
  1379. X    
  1380. X    /* do they want a special top line? */
  1381. X
  1382. X    firstline = getval("FIRSTLINE",Nullch);
  1383. X
  1384. X    /* custom line suppression, custom page ending */
  1385. X
  1386. X#ifdef CUSTOMLINES
  1387. X    if (hideline = getval("HIDELINE",Nullch))
  1388. X    compile(&hide_compex,hideline,TRUE,TRUE);
  1389. X    if (pagestop = getval("PAGESTOP",Nullch))
  1390. X    compile(&page_compex,pagestop,TRUE,TRUE);
  1391. X#endif
  1392. X
  1393. X    /* now read each unread article */
  1394. X
  1395. X    rc_changed = doing_ng = TRUE;    /* enter the twilight zone */
  1396. X    skipstate = 0;            /* we have not skipped anything (yet) */
  1397. X    checkcount = 0;            /* do not checkpoint for a while */
  1398. X    do_fseek = FALSE;            /* start 1st article at top */
  1399. X    if (art > lastart)
  1400. X#ifdef USETHREADS
  1401. X    first_art();
  1402. X#else
  1403. X    art=firstart;            /* init the for loop below */
  1404. X#endif
  1405. X    for (; art<=lastart+1; ) {        /* for each article */
  1406. X
  1407. X    /* do we need to "grow" the newsgroup? */
  1408. X
  1409. X#ifdef USETHREADS
  1410. X    if (ThreadedGroup) {
  1411. X        if ((art > lastart || forcegrow) && getngsize(ng) > total.last) {
  1412. X        unuse_data(1);        /* free data with selections saved */
  1413. X        if ((ThreadedGroup = use_data(thread_name(ngname))) != 0) {
  1414. X            grow_ctl(total.last);    /* sets lastart */
  1415. X            find_article(art);
  1416. X            curr_p_art = p_art;
  1417. X        }
  1418. X        forcegrow = FALSE;
  1419. X        }
  1420. X    }
  1421. X    else
  1422. X#endif
  1423. X    if (art > lastart || forcegrow)
  1424. X        grow_ctl(getngsize(ng));
  1425. X    check_first(art);        /* make sure firstart is still 1st */
  1426. X    if (start_command) {        /* fake up an initial command? */
  1427. X        prompt = whatnext;
  1428. X        strcpy(buf,start_command);
  1429. X        free(start_command);
  1430. X        start_command = Nullch;
  1431. X#ifdef USETHREADS
  1432. X        p_art = Nullart;
  1433. X#endif
  1434. X        art = lastart+1;
  1435. X        goto article_level;
  1436. X    }
  1437. X    if (art>lastart) {        /* are we off the end still? */
  1438. X        ART_NUM ucount = 0;        /* count of unread articles left */
  1439. X
  1440. X        for (i=firstart; i<=lastart; i++)
  1441. X        if (!(ctl_read(i)))
  1442. X            ucount++;        /* count the unread articles */
  1443. X#ifdef DEBUGGING
  1444. X        /*NOSTRICT*/
  1445. X        if (debug && ((ART_NUM)toread[ng]) != ucount)
  1446. X        printf("(toread=%ld sb %ld)",(long)toread[ng],(long)ucount)
  1447. X          FLUSH;
  1448. X#endif
  1449. X        /*NOSTRICT*/
  1450. X        toread[ng] = (ART_UNREAD)ucount;    /* this is perhaps pointless */
  1451. X        art = lastart + 1;        /* keep bitmap references sane */
  1452. X        if (art != curr_art) {
  1453. X#ifdef USETHREADS
  1454. X        recent_p_art = curr_p_art;
  1455. X        find_article(art);
  1456. X        curr_p_art = p_art;
  1457. X#endif
  1458. X        recent_art = curr_art;
  1459. X                    /* remember last article # (for '-') */
  1460. X        curr_art = art;      /* remember this article # */
  1461. X        }
  1462. X        if (erase_screen)
  1463. X        clear();            /* clear the screen */
  1464. X        else
  1465. X        fputs("\n\n",stdout) FLUSH;
  1466. X#ifdef VERBOSE
  1467. X        IF(verbose)
  1468. X        printf("End of newsgroup %s.",ngname);
  1469. X                    /* print pseudo-article */
  1470. X        ELSE
  1471. X#endif
  1472. X#ifdef TERSE
  1473. X        printf("End of %s",ngname);
  1474. X#endif
  1475. X#ifdef USETHREADS
  1476. X        if (ThreadedGroup)
  1477. X        ucount -= unthreaded;
  1478. X#endif
  1479. X        if (ucount) {
  1480. X#ifdef USETHREADS
  1481. X        if (selected_root_cnt)
  1482. X            printf("  (%ld + %ld articles still unread)",
  1483. X            (long)selected_count,(long)ucount-selected_count);
  1484. X        else
  1485. X#endif
  1486. X            printf("  (%ld article%s still unread)",
  1487. X            (long)ucount,ucount==1?nullstr:"s");
  1488. X        }
  1489. X        else {
  1490. X        if (!forcelast)
  1491. X            goto cleanup;    /* actually exit newsgroup */
  1492. X        }
  1493. X        prompt = whatnext;
  1494. X#ifdef ARTSEARCH
  1495. X        srchahead = 0;        /* no more subject search mode */
  1496. X#endif
  1497. X        fputs("\n\n",stdout) FLUSH;
  1498. X        skipstate = 0;        /* back to none skipped */
  1499. X    }
  1500. X    else if (!reread && was_read(art)) {
  1501. X                    /* has this article been read? */
  1502. X#ifdef USETHREADS
  1503. X        follow_thread('n');
  1504. X#else
  1505. X        art++;            /* then skip it */
  1506. X#endif
  1507. X        continue;
  1508. X    }
  1509. X    else if
  1510. X      (!reread && !was_read(art)
  1511. X#ifdef SERVER
  1512. X        && nntpopen(art,GET_HEADER) == Nullfp) { 
  1513. X#else
  1514. X        && artopen(art) == Nullfp) { /* never read it, & cannot find it? */
  1515. X        if (errno != ENOENT) {    /* has it not been deleted? */
  1516. X#ifdef VERBOSE
  1517. X        IF(verbose)
  1518. X            printf("\n(Article %ld exists but is unreadable.)\n",
  1519. X            (long)art) FLUSH;
  1520. X        ELSE
  1521. X#endif
  1522. X#ifdef TERSE
  1523. X            printf("\n(%ld unreadable.)\n",(long)art) FLUSH;
  1524. X#endif
  1525. X        skipstate = 0;
  1526. X        sleep(2);
  1527. X        }
  1528. X#endif
  1529. X        switch(skipstate++) {
  1530. X        case 0:
  1531. X        clear();
  1532. X#ifdef VERBOSE
  1533. X        IF(verbose)
  1534. X            fputs("Skipping unavailable article",stdout);
  1535. X        ELSE
  1536. X#endif
  1537. X#ifdef TERSE
  1538. X            fputs("Skipping",stdout);
  1539. X#endif
  1540. X        pad(just_a_sec/3);
  1541. X        sleep(1);
  1542. X        break;
  1543. X        case 1:
  1544. X        fputs("..",stdout);
  1545. X        fflush(stdout);
  1546. X        break;
  1547. X        default:
  1548. X        putchar('.');
  1549. X        fflush(stdout);
  1550. X#ifndef SERVER
  1551. X#define READDIR
  1552. X#ifdef READDIR
  1553. X        {            /* fast skip patch */
  1554. X            ART_NUM newart;
  1555. X            
  1556. X            if (! (newart=getngmin(".",art)))
  1557. X            newart = lastart+1;
  1558. X            for (i=art; i<newart; i++)
  1559. X            oneless(i);
  1560. X            art = newart - 1;
  1561. X        }
  1562. X#endif /* READDIR */
  1563. X#endif /* SERVER */
  1564. X        break;
  1565. X        }
  1566. X        oneless(art);        /* mark deleted as read */
  1567. X#ifdef USETHREADS
  1568. X        count_roots(FALSE);        /* Keep selected_count accurate */
  1569. X        find_article(art);
  1570. X        follow_thread('n');
  1571. X#else
  1572. X        art++;            /* try next article */
  1573. X#endif
  1574. X        continue;
  1575. X    }
  1576. X    else {                /* we have a real live article */
  1577. X        skipstate = 0;        /* back to none skipped */
  1578. X        if (art != curr_art) {
  1579. X#ifdef USETHREADS
  1580. X        recent_p_art = curr_p_art;
  1581. X        find_article(art);
  1582. X        curr_p_art = p_art;
  1583. X#endif
  1584. X        recent_art = curr_art;
  1585. X                    /* remember last article # (for '-') */
  1586. X        curr_art = art;      /* remember this article # */
  1587. X        }
  1588. X        if (!do_fseek) {        /* starting at top of article? */
  1589. X        artline = 0;        /* start at the beginning */
  1590. X        topline = -1;        /* and remember top line of screen */
  1591. X                    /*  (line # within article file) */
  1592. X        }
  1593. X        clear();            /* clear screen */
  1594. X        if (!artopen(art)) {    /* make sure article is found & open */
  1595. X#ifdef USETHREADS
  1596. X        char tmpbuf[256];
  1597. X        /* see if we have tree data for this article anyway */
  1598. X        init_tree();
  1599. X        sprintf(tmpbuf,"%s #%ld is not available.",ngname,(long)art);
  1600. X        tree_puts(tmpbuf,0,0);
  1601. X        vwtary((ART_LINE)0,(ART_POS)0);
  1602. X        finish_tree(1);
  1603. X        prompt = whatnext;
  1604. X#else
  1605. X        printf("Article %ld of %s is not available.\n\n",
  1606. X            (long)art,ngname) FLUSH;
  1607. X        prompt = whatnext;
  1608. X#endif
  1609. X#ifdef ARTSEARCH
  1610. X        srchahead = 0;
  1611. X#endif
  1612. X        }
  1613. X        else {            /* found it, so print it */
  1614. X        switch (do_article()) {
  1615. X        case DA_CLEAN:        /* quit newsgroup */
  1616. X            goto cleanup;
  1617. X        case DA_TOEND:        /* do not mark as read */
  1618. X            goto reask_article; 
  1619. X        case DA_RAISE:        /* reparse command at end of art */
  1620. X            goto article_level;
  1621. X        case DA_NORM:        /* normal end of article */
  1622. X            break;
  1623. X        }
  1624. X        }
  1625. X        if (art >= absfirst)    /* don't mark non-existant articles */
  1626. X        mark_as_read();        /* mark current article as read */
  1627. X        reread = FALSE;
  1628. X        do_hiding = TRUE;
  1629. X#ifdef ROTATION
  1630. X        rotate = FALSE;
  1631. X#endif
  1632. X    }
  1633. X
  1634. X/* if these gotos bother you, think of this as a little state machine */
  1635. X
  1636. Xreask_article:
  1637. X#ifdef MAILCALL
  1638. X    setmail();
  1639. X#endif
  1640. X    setdfltcmd();
  1641. X#ifdef CLEAREOL
  1642. X    if (erase_screen && can_home_clear)
  1643. X        clear_rest();
  1644. X#endif /* CLEAREOL */
  1645. X    unflush_output();        /* disable any ^O in effect */
  1646. X    standout();            /* enter standout mode */
  1647. X    printf(prompt,mailcall,dfltcmd);/* print prompt, whatever it is */
  1648. X    un_standout();            /* leave standout mode */
  1649. X    putchar(' ');
  1650. X    fflush(stdout);
  1651. Xreinp_article:
  1652. X    eat_typeahead();
  1653. X#ifdef PENDING
  1654. X    look_ahead();            /* see what we can do in advance */
  1655. X    if (!input_pending())
  1656. X        collect_subjects();        /* loads subject cache until */
  1657. X                    /* input is pending */
  1658. X#endif
  1659. X    getcmd(buf);
  1660. X    if (errno || *buf == '\f') {
  1661. X        if (LINES < 100 && !int_count)
  1662. X        *buf = '\f';        /* on CONT fake up refresh */
  1663. X        else {
  1664. X        putchar('\n') FLUSH;        /* but only on a crt */
  1665. X        goto reask_article;
  1666. X        }
  1667. X    }
  1668. Xarticle_level:
  1669. X
  1670. X    /* parse and process article level command */
  1671. X
  1672. X    switch (art_switch()) {
  1673. X    case AS_INP:            /* multichar command rubbed out */
  1674. X        goto reinp_article;
  1675. X    case AS_ASK:            /* reprompt "End of article..." */
  1676. X        goto reask_article;
  1677. X    case AS_CLEAN:            /* exit newsgroup */
  1678. X        goto cleanup;
  1679. X    case AS_NORM:            /* display article art */
  1680. X        break;
  1681. X    }
  1682. X    }                    /* end of article selection loop */
  1683. X    
  1684. X/* shut down newsgroup */
  1685. X
  1686. Xcleanup:
  1687. X    uud_end();
  1688. X#ifdef KILLFILES
  1689. X    kill_unwanted(firstart,"\nCleaning up...\n\n",FALSE);
  1690. X                    /* do cleanup from KILL file, if any */
  1691. X#endif
  1692. X#ifdef USETHREADS
  1693. X    if (ThreadedGroup)
  1694. X    unuse_data(0);            /* free article thread data */
  1695. X#endif
  1696. X    in_ng = FALSE;            /* leave newsgroup state */
  1697. X    if (artfp != Nullfp) {        /* article still open? */
  1698. X    fclose(artfp);            /* close it */
  1699. X    artfp = Nullfp;            /* and tell the world */
  1700. X#ifdef SERVER
  1701. X        sprintf(artname, "/tmp/rrn%ld.%ld", (long) openart, our_pid);
  1702. X        UNLINK(artname);
  1703. X#endif /* SERVER */
  1704. X    openart = 0;
  1705. X    }
  1706. X    putchar('\n') FLUSH;
  1707. X    yankback();                /* do a Y command */
  1708. X    restore_ng();            /* reconstitute .newsrc line */
  1709. X    doing_ng = FALSE;            /* tell sig_catcher to cool it */
  1710. X    free(ctlarea);            /* return the control area */
  1711. X#ifdef CACHESUBJ
  1712. X    if (subj_list) {
  1713. X    for (i=OFFSET(lastart); i>=0; --i)
  1714. X        if (subj_list[i])
  1715. X        free(subj_list[i]);
  1716. X#ifndef lint
  1717. X    free((char*)subj_list);
  1718. X#endif /* lint */
  1719. X    }
  1720. X#endif
  1721. X    write_rc();                /* and update .newsrc */
  1722. X    rc_changed = FALSE;            /* tell sig_catcher it is ok */
  1723. X    if (chdir(spool)) {
  1724. X    printf(nocd,spool) FLUSH;
  1725. X    sig_catcher(0);
  1726. X    }
  1727. X#ifdef KILLFILES
  1728. X    if (localkfp) {
  1729. X    fclose(localkfp);
  1730. X    localkfp = Nullfp;
  1731. X    }
  1732. X#endif
  1733. X    mode = oldmode;
  1734. X    return exit_code;
  1735. X}                    /* Whew! */
  1736. X
  1737. X/* decide what to do at the end of an article */
  1738. X
  1739. Xint
  1740. Xart_switch()
  1741. X{
  1742. X    register ART_NUM i;
  1743. X      
  1744. X    setdef(buf,dfltcmd);
  1745. X#ifdef VERIFY
  1746. X    printcmd();
  1747. X#endif
  1748. X
  1749. X    switch (*buf) {
  1750. X#ifdef USETHREADS
  1751. X    case '<':            /* goto previous thread */
  1752. X    if (!ThreadedGroup) {
  1753. X        goto group_unthreaded;
  1754. X    }
  1755. X    prev_root();
  1756. X    return AS_NORM;
  1757. X    case '>':            /* goto next thread */
  1758. X    if (!ThreadedGroup) {
  1759. X        goto group_unthreaded;
  1760. X    }
  1761. X    next_root();
  1762. X    return AS_NORM;
  1763. X    case 'U': {            /* unread some articles */
  1764. X    char *u_prompt, *u_help_thread;
  1765. X
  1766. X    if (!ThreadedGroup) {
  1767. X        dfltcmd = "a";
  1768. X        u_help_thread = nullstr;
  1769. X#ifdef VERBOSE
  1770. X        IF(verbose)
  1771. X        u_prompt = "\nSet unread: all articles? [an] ";
  1772. X        ELSE
  1773. X#endif
  1774. X#ifdef TERSE
  1775. X        u_prompt = "\nUnread? [an] ";
  1776. X#endif
  1777. X    }
  1778. X    else if (!p_art || art > lastart) {
  1779. X        dfltcmd = "+";
  1780. X        u_help_thread = nullstr;
  1781. X#ifdef VERBOSE
  1782. X        IF(verbose)
  1783. X        u_prompt = "\nSet unread: +select or all? [+an] ";
  1784. X        ELSE
  1785. X#endif
  1786. X#ifdef TERSE
  1787. X        u_prompt = "\nUnread? [+an] ";
  1788. X#endif
  1789. X    }
  1790. X    else {
  1791. X        dfltcmd = "t";
  1792. X#ifdef VERBOSE
  1793. X        IF(verbose) {
  1794. X        u_prompt = "\n\
  1795. XSet unread: thread, subthread, +select, or all? [ts+an] ";
  1796. X        u_help_thread = "\
  1797. XType t or SP to mark this thread's articles as unread.\n\
  1798. XType s to mark the current article and its descendants as unread.\n";
  1799. X        }
  1800. X        ELSE
  1801. X#endif
  1802. X#ifdef TERSE
  1803. X        {
  1804. X        u_prompt = "\nUnread? [ts+an] ";
  1805. X        u_help_thread = "\
  1806. Xt or SP to mark thread unread.\n\
  1807. Xs to mark subthread unread.\n";
  1808. X        }
  1809. X#endif
  1810. X    }
  1811. X      reask_unread:
  1812. X    in_char(u_prompt,'u');
  1813. X    setdef(buf,dfltcmd);
  1814. X#ifdef VERIFY
  1815. X    printcmd();
  1816. X#endif
  1817. X    putchar('\n') FLUSH;
  1818. X    if (*buf == 'h') {
  1819. X        fputs(u_help_thread,stdout);
  1820. X#ifdef VERBOSE
  1821. X        IF(verbose)
  1822. X        {
  1823. X        if (ThreadedGroup)
  1824. X            fputs("\
  1825. XType + to enter select thread mode using all the unread articles.\n\
  1826. X(The selected threads will be marked as unread and displayed as usual.)\n\
  1827. X",stdout) FLUSH;
  1828. X        fputs("\
  1829. XType a to mark all articles in this group as unread.\n\
  1830. XType n to change nothing.\n\
  1831. X",stdout) FLUSH;
  1832. X        }
  1833. X        ELSE
  1834. X#endif
  1835. X#ifdef TERSE
  1836. X        {
  1837. X        if (ThreadedGroup)
  1838. X            fputs("\
  1839. X+ to select threads from the unread.\n\
  1840. X",stdout) FLUSH;
  1841. X        fputs("\
  1842. Xa to mark all articles unread.\n\
  1843. Xn to change nothing.\n\
  1844. X",stdout) FLUSH;
  1845. X        }
  1846. X#endif
  1847. X        goto reask_unread;
  1848. X    }
  1849. X    else if (*buf == 'n' || *buf == 'q') {
  1850. X        return AS_ASK;
  1851. X    }
  1852. X    else if (*buf == 't' && *dfltcmd == 't')
  1853. X        follow_thread('u');
  1854. X    else if (*buf == 's' && *dfltcmd == 't') {
  1855. X        follow_thread('U');
  1856. X    }
  1857. X    else if (*buf == 'a') {
  1858. X        check_first(absfirst);
  1859. X        for (i = absfirst; i <= lastart; i++) {
  1860. X        onemore(i);        /* mark as unread */
  1861. X        }
  1862. X        scan_all_roots = FALSE;
  1863. X        count_roots(FALSE);
  1864. X        if (art > lastart) {
  1865. X        first_art();
  1866. X        }
  1867. X    }
  1868. X    else if (ThreadedGroup && *buf == '+') {
  1869. X        *buf = 'U';
  1870. X        goto select_threads;
  1871. X    }
  1872. X    else {
  1873. X        fputs(hforhelp,stdout) FLUSH;
  1874. X        settle_down();
  1875. X        goto reask_unread;
  1876. X    }
  1877. X    return AS_NORM;
  1878. X    }
  1879. X    case '[':            /* goto parent article */
  1880. X    case '{':            /* goto thread's root article */
  1881. X    if (p_art) {
  1882. X        if (!p_art->parent) {
  1883. X        if (p_art == p_articles + p_roots[p_art->root].articles) {
  1884. X            register char *cp = (*buf=='['?"parent":"root");
  1885. X#ifdef VERBOSE
  1886. X            IF(verbose)
  1887. X            fprintf(stdout,"\n\
  1888. XThere is no %s article prior to this one.\n",cp) FLUSH;
  1889. X            ELSE
  1890. X#endif
  1891. X#ifdef TERSE
  1892. X            fprintf(stdout,"\nNo prior %s.\n",cp) FLUSH;
  1893. X#endif
  1894. X            return AS_ASK;
  1895. X        }
  1896. X        *buf = '{';
  1897. X        p_art--;
  1898. X        }
  1899. X        else
  1900. X        p_art += p_art->parent;
  1901. X
  1902. X        if (*buf == '{')
  1903. X        while (p_art->parent)
  1904. X            p_art += p_art->parent;
  1905. X
  1906. X        art = p_art->num;
  1907. X        reread = TRUE;
  1908. X        return AS_NORM;
  1909. X    }
  1910. Xnot_threaded:
  1911. X    if (ThreadedGroup) {
  1912. X#ifdef VERBOSE
  1913. X        IF(verbose)
  1914. X        fputs("\nThis article is not threaded.\n",stdout) FLUSH;
  1915. X        ELSE
  1916. X#endif
  1917. X#ifdef TERSE
  1918. X        fputs("\nUnthreaded article.\n",stdout) FLUSH;
  1919. X#endif
  1920. X        return AS_ASK;
  1921. X    }
  1922. Xgroup_unthreaded:
  1923. X#ifdef VERBOSE
  1924. X    IF(verbose)
  1925. X        fputs("\nThis group is not threaded.\n",stdout) FLUSH;
  1926. X    ELSE
  1927. X#endif
  1928. X#ifdef TERSE
  1929. X        fputs("\nUnthreaded group.\n",stdout) FLUSH;
  1930. X#endif
  1931. X    return AS_ASK;
  1932. X    case ']':            /* goto child article */
  1933. X    case '}':            /* goto thread's leaf article */
  1934. X    if (p_art) {
  1935. X        if (!(p_art++)->child_cnt) {
  1936. X        PACKED_ARTICLE *root_limit = upper_limit(p_art-1,FALSE);
  1937. X
  1938. X        if (p_art == root_limit) {
  1939. X#ifdef VERBOSE
  1940. X            IF(verbose)
  1941. X            fputs("\n\
  1942. XThis is the last leaf in this tree.\n",stdout) FLUSH;
  1943. X            ELSE
  1944. X#endif
  1945. X#ifdef TERSE
  1946. X            fputs("\nLast leaf.\n",stdout) FLUSH;
  1947. X#endif
  1948. X            p_art--;
  1949. X            return AS_ASK;
  1950. X        }
  1951. X        if (*buf == ']')
  1952. X            *buf = '}';
  1953. X        else {
  1954. X            while (++p_art != root_limit && p_art->parent)
  1955. X            ;
  1956. X            p_art--;
  1957. X            *buf = ' ';
  1958. X        }
  1959. X        }
  1960. X        if( *buf == '}' )
  1961. X        while (p_art->child_cnt)
  1962. X            p_art++;
  1963. X
  1964. X        art = p_art->num;
  1965. X        reread = TRUE;
  1966. X        return AS_NORM;
  1967. X    }
  1968. X    goto not_threaded;
  1969. X    case 'T':
  1970. X    if (p_art) {
  1971. X        sprintf(buf,"T%ld\t# %s",(long)p_roots[p_art->root].root_num,
  1972. X        subject_ptrs[p_art->subject]);
  1973. X        fputs(buf,stdout);
  1974. X        kf_append(buf);
  1975. X        *buf = 'J';
  1976. X        goto follow_threads;
  1977. X    }
  1978. X    goto not_threaded;
  1979. X    case 'K':
  1980. X    if (p_art) {
  1981. X        /* first, write kill-subject command */
  1982. X        (void)art_search(buf, (sizeof buf), TRUE);
  1983. X        art = curr_art;
  1984. X        p_art = curr_p_art;
  1985. X        *buf = 'k';            /* then take care of any prior subjs */
  1986. X        goto follow_threads;
  1987. X    }
  1988. X    goto normal_search;
  1989. X    case ',':        /* kill this node and all descendants */
  1990. X    mark_as_read();
  1991. X    *buf = 'K';
  1992. X    case 'k':        /* kill current subject # (e.g. [1]) */
  1993. X    case 'J':        /* Junk all nodes in this thread */
  1994. X    if (!ThreadedGroup) {
  1995. X        *buf = 'k';
  1996. X        goto normal_search;
  1997. X    }
  1998. Xfollow_threads:
  1999. X    follow_thread(*buf);
  2000. X    if (!reread && !toread[ng])
  2001. X        return AS_CLEAN;
  2002. X    if (!reread && selected_root_cnt && !selected_count)
  2003. X        goto select_threads;
  2004. X    return AS_NORM;
  2005. X    case 't':
  2006. X    carriage_return();
  2007. X#ifndef CLEAREOL
  2008. X    erase_eol();        /* erase the prompt */
  2009. X#else
  2010. X    if (erase_screen && can_home_clear)
  2011. X        clear_rest();
  2012. X    else
  2013. X        erase_eol();    /* erase the prompt */
  2014. X#endif /* CLEAREOL */
  2015. X    fflush(stdout);
  2016. X    page_line = 1;
  2017. X    p_art = curr_p_art;
  2018. X    entire_tree();
  2019. X    return AS_ASK;
  2020. X    case ':':            /* execute command on selected articles */
  2021. X    if (!ThreadedGroup) {
  2022. X        goto group_unthreaded;
  2023. X    }
  2024. X    page_line = 1;
  2025. X    if (!use_selected())
  2026. X        return AS_INP;
  2027. X    putchar('\n');
  2028. X    art = curr_art;
  2029. X    p_art = curr_p_art;
  2030. X    return AS_ASK;
  2031. X#endif /* USETHREADS */
  2032. X    case 'p':            /* find previous unread article */
  2033. X#ifdef USETHREADS
  2034. X    if (ThreadedGroup) {
  2035. X        goto backtrack_threads;
  2036. X    }
  2037. X#endif
  2038. X    do {
  2039. X        if (art <= firstart)
  2040. X        break;
  2041. X        art--;
  2042. X#ifdef SERVER
  2043. X    } while (was_read(art) || nntpopen(art,GET_HEADER) == Nullfp);
  2044. X#else
  2045. X    } while (was_read(art) || artopen(art) == Nullfp);
  2046. X#endif
  2047. X#ifdef ARTSEARCH
  2048. X    srchahead = 0;
  2049. X#endif
  2050. X    return AS_NORM;
  2051. X    case 'P':        /* goto previous article */
  2052. X#ifdef USETHREADS
  2053. X    if (ThreadedGroup) {
  2054. Xbacktrack_threads:
  2055. X        backtrack_thread( *buf );
  2056. X        art++;        /* prepare for art-- below */
  2057. X    }
  2058. X#endif
  2059. X    if (art > absfirst)
  2060. X        art--;
  2061. X    else {
  2062. X#ifdef VERBOSE
  2063. X        IF(verbose)
  2064. X        fprintf(stdout,"\n\
  2065. XThere are no%s articles prior to this one.\n\
  2066. X",*buf=='P'?nullstr:" unread") FLUSH;
  2067. X        ELSE
  2068. X#endif
  2069. X#ifdef TERSE
  2070. X        fprintf(stdout,"\n\
  2071. XNo previous%s articles\n\
  2072. X",*buf=='P'?nullstr:" unread") FLUSH;
  2073. X#endif
  2074. X        art = curr_art;
  2075. X#ifdef USETHREADS
  2076. X        p_art = curr_p_art;
  2077. X#endif
  2078. X        return AS_ASK;
  2079. X    }
  2080. X    reread = TRUE;
  2081. X#ifdef ARTSEARCH
  2082. X    srchahead = 0;
  2083. X#endif
  2084. X    return AS_NORM;
  2085. X    case '-':
  2086. X    if (recent_art >= 0) {
  2087. X#ifdef USETHREADS
  2088. X        p_art = recent_p_art;
  2089. X#endif
  2090. X        art = recent_art;
  2091. X        reread = TRUE;
  2092. X#ifdef ARTSEARCH
  2093. X        srchahead = -(srchahead != 0);
  2094. X#endif
  2095. X        return AS_NORM;
  2096. X    }
  2097. X    else {
  2098. X        exit_code = NG_MINUS;
  2099. X        return AS_CLEAN;
  2100. X    }
  2101. X    case 'n':        /* find next unread article? */
  2102. X#ifdef USETHREADS
  2103. X    if (ThreadedGroup) {
  2104. X        goto follow_threads;
  2105. X    }
  2106. X#endif
  2107. X    if (art > lastart) {
  2108. X        if (!toread[ng])
  2109. X        return AS_CLEAN;
  2110. X        art = firstart;
  2111. X    }
  2112. X#ifdef ARTSEARCH
  2113. X    else if (scanon && srchahead) {
  2114. X        *buf = Ctl('n');
  2115. X        goto normal_search;
  2116. X    }
  2117. X#endif
  2118. X    else
  2119. X        art++;
  2120. X
  2121. X#ifdef ARTSEARCH
  2122. X    srchahead = 0;
  2123. X#endif
  2124. X    return AS_NORM;
  2125. X    case 'N':            /* goto next article */
  2126. X#ifdef USETHREADS
  2127. X    if (ThreadedGroup) {
  2128. X        goto follow_threads;
  2129. X    }
  2130. X#endif
  2131. X    if (art > lastart)
  2132. X        art = absfirst;
  2133. X    else
  2134. X        art++;
  2135. X    if (art <= lastart)
  2136. X        reread = TRUE;
  2137. X#ifdef ARTSEARCH
  2138. X    srchahead = 0;
  2139. X#endif
  2140. X    return AS_NORM;
  2141. X    case '$':
  2142. X    art = lastart+1;
  2143. X    forcelast = TRUE;
  2144. X#ifdef USETHREADS
  2145. X    p_art = Nullart;
  2146. X#endif
  2147. X#ifdef ARTSEARCH
  2148. X    srchahead = 0;
  2149. X#endif
  2150. X    return AS_NORM;
  2151. X    case '1': case '2': case '3':    /* goto specified article */
  2152. X    case '4': case '5': case '6':    /* or do something with a range */
  2153. X    case '7': case '8': case '9': case '.':
  2154. X    forcelast = TRUE;
  2155. X    switch (numnum()) {
  2156. X    case NN_INP:
  2157. X        return AS_INP;
  2158. X    case NN_ASK:
  2159. X        return AS_ASK;
  2160. X    case NN_REREAD:
  2161. X        reread = TRUE;
  2162. X#ifdef ARTSEARCH
  2163. X        if (srchahead)
  2164. X        srchahead = -1;
  2165. X#endif
  2166. X        break;
  2167. X    case NN_NORM:
  2168. X        if (was_read(art)) {
  2169. X#ifdef USETHREADS
  2170. X        first_art();
  2171. X#else
  2172. X        art = firstart;
  2173. X#endif
  2174. X        pad(just_a_sec/3);
  2175. X        }
  2176. X        else {
  2177. X        putchar('\n');
  2178. X        return AS_ASK;
  2179. X        }
  2180. X        break;
  2181. X    }
  2182. X    return AS_NORM;
  2183. X    case Ctl('k'):
  2184. X    edit_kfile();
  2185. X    return AS_ASK;
  2186. X#ifndef USETHREADS
  2187. X    case 'K':
  2188. X    case 'k':
  2189. X#endif
  2190. X    case Ctl('n'):    /* search for next article with same subject */
  2191. X#ifdef USETHREADS
  2192. X    if (ThreadedGroup) {
  2193. X        goto follow_threads;
  2194. X    }
  2195. X#endif
  2196. X    case Ctl('p'):    /* search for previous article with same subject */
  2197. X#ifdef USETHREADS
  2198. X    if (ThreadedGroup) {
  2199. X        goto backtrack_threads;
  2200. X    }
  2201. X#endif
  2202. X    case '/': case '?':
  2203. Xnormal_search:
  2204. X#ifdef ARTSEARCH
  2205. X    {        /* search for article by pattern */
  2206. X    char cmd = *buf;
  2207. X    
  2208. X    reread = TRUE;        /* assume this */
  2209. X    page_line = 1;
  2210. X    switch (art_search(buf, (sizeof buf), TRUE)) {
  2211. X    case SRCH_ERROR:
  2212. X        art = curr_art;
  2213. X        return AS_ASK;
  2214. X    case SRCH_ABORT:
  2215. X        art = curr_art;
  2216. X        return AS_INP;
  2217. X    case SRCH_INTR:
  2218. X#ifdef VERBOSE
  2219. X        IF(verbose)
  2220. X        printf("\n(Interrupted at article %ld)\n",(long)art) FLUSH;
  2221. X        ELSE
  2222. X#endif
  2223. X#ifdef TERSE
  2224. X        printf("\n(Intr at %ld)\n",(long)art) FLUSH;
  2225. X#endif
  2226. X        art = curr_art;
  2227. X                /* restore to current article */
  2228. X        return AS_ASK;
  2229. X    case SRCH_DONE:
  2230. X        fputs("done\n",stdout) FLUSH;
  2231. X        pad(just_a_sec/3);    /* 1/3 second */
  2232. X        if (!srchahead) {
  2233. X        art = curr_art;
  2234. X        return AS_ASK;
  2235. X        }
  2236. X#ifdef USETHREADS
  2237. X        first_art();
  2238. X#else
  2239. X        art = firstart;
  2240. X#endif
  2241. X        reread = FALSE;
  2242. X        return AS_NORM;
  2243. X    case SRCH_SUBJDONE:
  2244. X#ifdef UNDEF
  2245. X        fputs("\n\n\n\nSubject not found.\n",stdout) FLUSH;
  2246. X        pad(just_a_sec/3);    /* 1/3 second */
  2247. X#endif
  2248. X#ifdef USETHREADS
  2249. X        first_art();
  2250. X#else
  2251. X        art = firstart;
  2252. X#endif
  2253. X        reread = FALSE;
  2254. X        return AS_NORM;
  2255. X    case SRCH_NOTFOUND:
  2256. X        fputs("\n\n\n\nNot found.\n",stdout) FLUSH;
  2257. X        art = curr_art;  /* restore to current article */
  2258. X        return AS_ASK;
  2259. X    case SRCH_FOUND:
  2260. X        if (cmd == Ctl('n') || cmd == Ctl('p'))
  2261. X        oldsubject = TRUE;
  2262. X        break;
  2263. X    }
  2264. X    return AS_NORM;
  2265. X    }
  2266. X#else
  2267. X    buf[1] = '\0';
  2268. X    notincl(buf);
  2269. X    return AS_ASK;
  2270. X#endif
  2271. X    case 'u':            /* unsubscribe from this newsgroup? */
  2272. X    rcchar[ng] = NEGCHAR;
  2273. X    return AS_CLEAN;
  2274. X    case 'M':
  2275. X#ifdef DELAYMARK
  2276. X    if (art <= lastart) {
  2277. X        delay_unmark(art);
  2278. X        printf("\nArticle %ld will return.\n",(long)art) FLUSH;
  2279. X    }
  2280. X#else
  2281. X    notincl("M");
  2282. X#endif
  2283. X    return AS_ASK;
  2284. X    case 'm':
  2285. X    if (art <= lastart) {
  2286. X        unmark_as_read();
  2287. X        printf("\nArticle %ld marked as still unread.\n",(long)art) FLUSH;
  2288. X    }
  2289. X    return AS_ASK;
  2290. X    case 'c':            /* catch up */
  2291. X      reask_catchup:
  2292. X#ifdef VERBOSE
  2293. X    IF(verbose)
  2294. X        in_char("\nDo you really want to mark everything as read? [yn] ",
  2295. X        'C');
  2296. X    ELSE
  2297. X#endif
  2298. X#ifdef TERSE
  2299. X        in_char("\nReally? [ynh] ", 'C');
  2300. X#endif
  2301. X    setdef(buf,"y");
  2302. X#ifdef VERIFY
  2303. X    printcmd();
  2304. X#endif
  2305. X    putchar('\n') FLUSH;
  2306. X    if (*buf == 'h') {
  2307. X#ifdef VERBOSE
  2308. X        IF(verbose)
  2309. X        fputs("\
  2310. XType y or SP to mark all articles as read.\n\
  2311. XType n to leave articles marked as they are.\n\
  2312. XType u to mark everything read and unsubscribe.\n\
  2313. X",stdout) FLUSH;
  2314. X        ELSE
  2315. X#endif
  2316. X#ifdef TERSE
  2317. X        fputs("\
  2318. Xy or SP to mark all read.\n\
  2319. Xn to forget it.\n\
  2320. Xu to mark all and unsubscribe.\n\
  2321. X",stdout) FLUSH;
  2322. X#endif
  2323. X        goto reask_catchup;
  2324. X    }
  2325. X    else if (*buf == 'n' || *buf == 'q') {
  2326. X        return AS_ASK;
  2327. X    }
  2328. X    else if (*buf != 'y' && *buf != 'u') {
  2329. X        fputs(hforhelp,stdout) FLUSH;
  2330. X        settle_down();
  2331. X        goto reask_catchup;
  2332. X    }
  2333. X    for (i = firstart; i <= lastart; i++) {
  2334. X        oneless(i);        /* mark as read */
  2335. X    }
  2336. X#ifdef USETHREADS
  2337. X    selected_root_cnt = selected_count = 0;
  2338. X#endif
  2339. X#ifdef DELAYMARK
  2340. X    if (dmfp)
  2341. X        yankback();
  2342. X#endif
  2343. X    if (*buf == 'u') {
  2344. X        rcchar[ng] = NEGCHAR;
  2345. X        return AS_CLEAN;
  2346. X    }
  2347. X#ifdef USETHREADS
  2348. X    p_art = Nullart;
  2349. X    selected_count = 0;
  2350. X#endif
  2351. X    art = lastart+1;
  2352. X    forcelast = FALSE;
  2353. X    return AS_NORM;
  2354. X    case 'Q':
  2355. X    exit_code = NG_ASK;
  2356. X    /* FALL THROUGH */
  2357. X    case 'q':            /* go back up to newsgroup level? */
  2358. X    return AS_CLEAN;
  2359. X    case 'j':
  2360. X    putchar('\n') FLUSH;
  2361. X    if (art <= lastart)
  2362. X        mark_as_read();
  2363. X    return AS_ASK;
  2364. X    case 'h': {            /* help? */
  2365. X    int cmd;
  2366. X
  2367. X    if ((cmd = help_art()) > 0)
  2368. X        pushchar(cmd);
  2369. X    return AS_ASK;
  2370. X    }
  2371. X    case '&':
  2372. X    if (switcheroo()) /* get rest of command */
  2373. X        return AS_INP;    /* if rubbed out, try something else */
  2374. X    return AS_ASK;
  2375. X    case '#':
  2376. X#ifdef VERBOSE
  2377. X    IF(verbose)
  2378. X        printf("\nThe last article is %ld.\n",(long)lastart) FLUSH;
  2379. X    ELSE
  2380. X#endif
  2381. X#ifdef TERSE
  2382. X        printf("\n%ld\n",(long)lastart) FLUSH;
  2383. X#endif
  2384. X    return AS_ASK;
  2385. X#ifdef USETHREADS
  2386. X    case '+':            /* enter thread selection mode */
  2387. X    if (ThreadedGroup) {
  2388. Xselect_threads:
  2389. X        *buf = select_thread(*buf);
  2390. X        if (*buf == 'q') {
  2391. X        putchar( '\n' ) FLUSH;
  2392. X        return AS_ASK;
  2393. X        }
  2394. X        if (*buf == 'Q') {
  2395. X        exit_code = NG_ASK;
  2396. X        return AS_CLEAN;
  2397. X        }
  2398. X        if (*buf == 'N' || !toread[ng])
  2399. X        return AS_CLEAN;
  2400. X        return AS_NORM;
  2401. X    }
  2402. X    /* FALLTHROUGH */
  2403. X#endif
  2404. X    case '=': {            /* list subjects */
  2405. X    char tmpbuf[256];
  2406. X    ART_NUM oldart = art;
  2407. X    int cmd;
  2408. X    char *subjline = getval("SUBJLINE",Nullch);
  2409. X#ifndef CACHESUBJ
  2410. X    char *s;
  2411. X#endif
  2412. X
  2413. X    page_init();
  2414. X#ifdef CACHESUBJ
  2415. X    if (!subj_list)
  2416. X        fetchsubj(art,TRUE,FALSE);
  2417. X#endif
  2418. X    for (i=firstart; i<=lastart && !int_count; i++) {
  2419. X#ifdef CACHESUBJ
  2420. X        if (!was_read(i) &&
  2421. X          (subj_list[OFFSET(i)] != Nullch || fetchsubj(i,FALSE,FALSE)) &&
  2422. X          *subj_list[OFFSET(i)] ) {
  2423. X        sprintf(tmpbuf,"%5ld ", i);
  2424. X        if (subjline) {
  2425. X            art = i;
  2426. X            interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  2427. X        }
  2428. X        else
  2429. X            safecpy(tmpbuf + 6, subj_list[OFFSET(i)],
  2430. X            (sizeof tmpbuf) - 6);
  2431. X        if (cmd = print_lines(tmpbuf,NOMARKING)) {
  2432. X            if (cmd > 0)
  2433. X            pushchar(cmd);
  2434. X            break;
  2435. X        }
  2436. X        }
  2437. X#else
  2438. X        if (!was_read(i) && (s = fetchsubj(i,FALSE,FALSE)) && *s) {
  2439. X        sprintf(tmpbuf,"%5ld ", i);
  2440. X        if (subjline) {    /* probably fetches it again! */
  2441. X            art = i;
  2442. X            interp(tmpbuf + 6, (sizeof tmpbuf) - 6, subjline);
  2443. X        }
  2444. X        else
  2445. X            safecpy(tmpbuf + 6, s, (sizeof tmpbuf) - 6);
  2446. X        if (cmd = print_lines(tmpbuf,NOMARKING)) {
  2447. X            if (cmd > 0)
  2448. X            pushchar(cmd);
  2449. X            break;
  2450. X        }
  2451. X        }
  2452. X#endif
  2453. X    }
  2454. X    int_count = 0;
  2455. X    art = oldart;
  2456. X    return AS_ASK;
  2457. X    }
  2458. X    case '^':
  2459. X#ifdef USETHREADS
  2460. X    first_art();
  2461. X#else
  2462. X    art = firstart;
  2463. X#endif
  2464. X#ifdef ARTSEARCH
  2465. X    srchahead = 0;
  2466. X#endif
  2467. X    return AS_NORM;
  2468. X#if defined(CACHESUBJ) && defined(DEBUGGING)
  2469. X    case 'D':
  2470. X    printf("\nFirst article: %ld\n",(long)firstart) FLUSH;
  2471. X    if (!subj_list)
  2472. X        fetchsubj(art,TRUE,FALSE);
  2473. X    if (subj_list != Null(char **)) {
  2474. X        for (i=1; i<=lastart && !int_count; i++) {
  2475. X        if (subj_list[OFFSET(i)])
  2476. X            printf("%5ld %c %s\n",
  2477. X            i, (was_read(i)?'y':'n'), subj_list[OFFSET(i)]) FLUSH;
  2478. X        }
  2479. X    }
  2480. X    int_count = 0;
  2481. X    return AS_ASK;
  2482. X#endif
  2483. X    case 'v':
  2484. X    if (art <= lastart) {
  2485. X        reread = TRUE;
  2486. X        do_hiding = FALSE;
  2487. X    }
  2488. X    return AS_NORM;
  2489. X#ifdef ROTATION
  2490. X    case Ctl('x'):
  2491. X#endif
  2492. X    case Ctl('r'):
  2493. X#ifdef ROTATION
  2494. X    rotate = (*buf==Ctl('x'));
  2495. X#endif
  2496. X    if (art <= lastart)
  2497. X        reread = TRUE;
  2498. X    return AS_NORM;
  2499. X#ifdef ROTATION
  2500. X    case 'X':
  2501. X    rotate = !rotate;
  2502. X    /* FALL THROUGH */
  2503. X#else
  2504. X    case Ctl('x'):
  2505. X    case 'x':
  2506. X    case 'X':
  2507. X    notincl("x");
  2508. X    return AS_ASK;
  2509. X#endif
  2510. X    case 'l': case Ctl('l'):        /* refresh screen */
  2511. X    if (art <= lastart) {
  2512. X        reread = TRUE;
  2513. X        clear();
  2514. X        do_fseek = TRUE;
  2515. X        artline = topline;
  2516. X        if (artline < 0)
  2517. X        artline = 0;
  2518. X    }
  2519. X    return AS_NORM;
  2520. X    case 'b': case Ctl('b'):        /* back up a page */
  2521. X    if (art <= lastart) {
  2522. X        ART_LINE target;
  2523. X
  2524. X        reread = TRUE;
  2525. X        clear();
  2526. X        do_fseek = TRUE;
  2527. X        target = topline - (LINES - 2);
  2528. X        artline = topline;
  2529. X        if (artline >= 0) do {
  2530. X        artline--;
  2531. X        } while(artline >= 0 && artline > target && vrdary(artline-1) >= 0);
  2532. X        topline = artline;
  2533. X        if (artline < 0)
  2534. X        artline = 0;
  2535. X    }
  2536. X    return AS_NORM;
  2537. X    case '!':            /* shell escape */
  2538. X    if (escapade())
  2539. X        return AS_INP;
  2540. X    return AS_ASK;
  2541. X    case 'C': {
  2542. X    cancel_article();
  2543. X    return AS_ASK;
  2544. X    }
  2545. X    case 'R':
  2546. X    case 'r': {            /* reply? */
  2547. X    reply();
  2548. X    return AS_ASK;
  2549. X    }
  2550. X    case 'F':
  2551. X    case 'f': {            /* followup command */
  2552. X    followup();
  2553. X    forcegrow = TRUE;        /* recalculate lastart */
  2554. X    return AS_ASK;
  2555. X    }
  2556. X    case '|':
  2557. X    case 'w': case 'W':
  2558. X    case 's': case 'S':        /* save command */
  2559. X    case 'e':            /* extract command */
  2560. X    if (save_article() == SAVE_ABORT)
  2561. X        return AS_INP;
  2562. X    int_count = 0;
  2563. X    return AS_ASK;
  2564. X    case 'E':
  2565. X    if (uu_out != Nullfp) {
  2566. X        uud_end();
  2567. X    }
  2568. X    return AS_ASK;
  2569. X#ifdef DELAYMARK
  2570. X    case 'Y':                /* yank back M articles */
  2571. X    yankback();
  2572. X#ifdef USETHREADS
  2573. X    first_art();
  2574. X#else
  2575. X    art = firstart;            /* from the beginning */
  2576. X#endif
  2577. X    return AS_NORM;            /* pretend nothing happened */
  2578. X#endif
  2579. X#ifdef STRICTCR
  2580. X    case '\n':
  2581. X    fputs(badcr,stdout) FLUSH;
  2582. X    return AS_ASK;
  2583. X#endif
  2584. X    default:
  2585. X    printf("\n%s",hforhelp) FLUSH;
  2586. X    settle_down();
  2587. X    return AS_ASK;
  2588. X    }
  2589. X}
  2590. X
  2591. X#ifdef MAILCALL
  2592. X/* see if there is any mail */
  2593. X
  2594. Xvoid
  2595. Xsetmail()
  2596. X{
  2597. X    if (! (mailcount++)) {
  2598. X    char *mailfile = filexp(getval("MAILFILE",MAILFILE));
  2599. X    
  2600. X    if (stat(mailfile,&filestat) < 0 || !filestat.st_size
  2601. X        || filestat.st_atime > filestat.st_mtime)
  2602. X        mailcall = nullstr;
  2603. X    else
  2604. X        mailcall = getval("MAILCALL","(Mail) ");
  2605. X    }
  2606. X    mailcount %= 10;            /* check every 10 articles */
  2607. X}
  2608. X#endif
  2609. X
  2610. Xvoid
  2611. Xsetdfltcmd()
  2612. X{
  2613. X#ifdef USETHREADS
  2614. X    if (toread[ng] == unthreaded) {
  2615. X#else
  2616. X    if (!toread[ng]) {
  2617. X#endif
  2618. X    if (art > lastart)
  2619. X        dfltcmd = "qnp";
  2620. X    else
  2621. X        dfltcmd = "npq";
  2622. X    }
  2623. X    else {
  2624. X#ifdef USETHREADS
  2625. X    if (selected_root_cnt && !selected_count)
  2626. X        dfltcmd = "+npq";
  2627. X    else
  2628. X# ifdef ARTSEARCH
  2629. X    if (!ThreadedGroup && srchahead)
  2630. X        dfltcmd = "^Nnpq";
  2631. X    else
  2632. X# endif
  2633. X#else
  2634. X# ifdef ARTSEARCH
  2635. X    if (srchahead)
  2636. X        dfltcmd = "^Nnpq";
  2637. X    else
  2638. X# endif
  2639. X#endif
  2640. X        dfltcmd = "npq";
  2641. X    }
  2642. X}
  2643. END_OF_FILE
  2644.   if test 34884 -ne `wc -c <'ng.c'`; then
  2645.     echo shar: \"'ng.c'\" unpacked with wrong size!
  2646.   fi
  2647.   # end of 'ng.c'
  2648. fi
  2649. echo shar: End of archive 4 \(of 14\).
  2650. cp /dev/null ark4isdone
  2651. MISSING=""
  2652. for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 ; do
  2653.     if test ! -f ark${I}isdone ; then
  2654.     MISSING="${MISSING} ${I}"
  2655.     fi
  2656. done
  2657. if test "${MISSING}" = "" ; then
  2658.     echo You have unpacked all 14 archives.
  2659.     rm -f ark[1-9]isdone ark[1-9][0-9]isdone
  2660. else
  2661.     echo You still must unpack the following archives:
  2662.     echo "        " ${MISSING}
  2663. fi
  2664. exit 0
  2665.